X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fworld%2Fchunk.cpp;h=7f2233e2def66a6e99dee791d6d2e0ce1a73b0ad;hb=3185bad87c06739e4ec19b456c7158437ba9621f;hp=452e7aa3b3cf23345c7cb1e7f085e3c5d16572c5;hpb=c3397eb26a844ded6ddbf92c95cbb87cd3baf65d;p=blank.git diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index 452e7aa..7f2233e 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -8,56 +8,67 @@ #include "Generator.hpp" #include "WorldCollision.hpp" #include "../app/Assets.hpp" +#include "../geometry/distance.hpp" #include "../graphics/BlockLighting.hpp" +#include "../graphics/BlockMesh.hpp" #include "../graphics/Viewport.hpp" #include "../io/WorldSave.hpp" -#include "../model/BlockModel.hpp" #include #include #include #include +#include +#include + namespace blank { -constexpr int Chunk::width; -constexpr int Chunk::height; -constexpr int Chunk::depth; +constexpr int Chunk::side; constexpr int Chunk::size; Chunk::Chunk(const BlockTypeRegistry &types) noexcept : types(&types) , neighbor{0} -, blocks{} +, gravity() , light{0} , generated(false) , lighted(false) , position(0, 0, 0) , ref_count(0) -, dirty_model(false) +, dirty_mesh(false) , dirty_save(false) { } Chunk::Chunk(Chunk &&other) noexcept : types(other.types) +, gravity(std::move(other.gravity)) +, generated(other.generated) +, lighted(other.lighted) , position(other.position) -, dirty_model(other.dirty_model) +, ref_count(other.ref_count) +, dirty_mesh(other.dirty_mesh) , dirty_save(other.dirty_save) { std::copy(other.neighbor, other.neighbor + sizeof(neighbor), neighbor); std::copy(other.blocks, other.blocks + sizeof(blocks), blocks); std::copy(other.light, other.light + sizeof(light), light); + other.ref_count = 0; } Chunk &Chunk::operator =(Chunk &&other) noexcept { types = other.types; std::copy(other.neighbor, other.neighbor + sizeof(neighbor), neighbor); + gravity = std::move(other.gravity); std::copy(other.blocks, other.blocks + sizeof(blocks), blocks); std::copy(other.light, other.light + sizeof(light), light); + generated = other.generated; + lighted = other.lighted; position = other.position; - dirty_model = other.dirty_save; + std::swap(ref_count, other.ref_count); + dirty_mesh = other.dirty_save; dirty_save = other.dirty_save; return *this; } @@ -68,9 +79,9 @@ namespace { struct SetNode { Chunk *chunk; - Chunk::Pos pos; + RoughLocation::Fine pos; - SetNode(Chunk *chunk, Chunk::Pos pos) + SetNode(Chunk *chunk, RoughLocation::Fine pos) : chunk(chunk), pos(pos) { } int Get() const noexcept { return chunk->GetLight(pos); } @@ -78,6 +89,9 @@ struct SetNode { const BlockType &GetType() const noexcept { return chunk->Type(Chunk::ToIndex(pos)); } + int EmitLevel() const noexcept { return GetType().luminosity; } + bool EmitsLight() const noexcept { return EmitLevel() > 0; } + bool HasNext(Block::Face face) noexcept { const BlockType &type = GetType(); if (type.block_light && !type.luminosity) return false; @@ -96,10 +110,10 @@ struct UnsetNode int level; - UnsetNode(Chunk *chunk, Chunk::Pos pos) + UnsetNode(Chunk *chunk, RoughLocation::Fine pos) : SetNode(chunk, pos), level(Get()) { } - UnsetNode(const SetNode &set) + explicit UnsetNode(const SetNode &set) : SetNode(set), level(Get()) { } @@ -140,9 +154,13 @@ void work_dark() noexcept { for (int face = 0; face < Block::FACE_COUNT; ++face) { if (node.HasNext(Block::Face(face))) { UnsetNode other = node.GetNext(Block::Face(face)); - // TODO: if there a light source here with the same level this will err if (other.Get() != 0 && other.Get() < node.level) { - other.Set(0); + if (other.EmitsLight()) { + other.Set(other.EmitLevel()); + light_queue.emplace(other); + } else { + other.Set(0); + } dark_queue.emplace(other); } else { light_queue.emplace(other); @@ -161,6 +179,12 @@ void Chunk::SetBlock(int index, const Block &block) noexcept { blocks[index] = block; Invalidate(); + if (old_type.gravity && !new_type.gravity) { + gravity.erase(index); + } else if (new_type.gravity && !old_type.gravity) { + gravity.insert(index); + } + if (!lighted || &old_type == &new_type) return; if (new_type.luminosity > old_type.luminosity) { @@ -187,7 +211,7 @@ 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)); + RoughLocation::Fine pos(ToPos(index)); for (int face = 0; face < Block::FACE_COUNT; ++face) { BlockLookup next_block(this, pos, Block::Face(face)); if (next_block) { @@ -204,10 +228,10 @@ void Chunk::SetBlock(int index, const Block &block) noexcept { void Chunk::ScanLights() { int idx = 0; - Pos pos(0, 0, 0); - for (; pos.z < depth; ++pos.z) { - for (pos.y = 0; pos.y < height; ++pos.y) { - for (pos.x = 0; pos.x < width; ++pos.x, ++idx) { + RoughLocation::Fine pos(0, 0, 0); + for (; pos.z < side; ++pos.z) { + for (pos.y = 0; pos.y < side; ++pos.y) { + for (pos.x = 0; pos.x < side; ++pos.x, ++idx) { const BlockType &type = Type(blocks[idx]); if (type.luminosity) { SetLight(idx, type.luminosity); @@ -220,6 +244,15 @@ void Chunk::ScanLights() { lighted = true; } +void Chunk::ScanActive() { + gravity.clear(); + for (int index = 0; index < size; ++index) { + if (Type(index).gravity) { + gravity.insert(gravity.end(), index); + } + } +} + void Chunk::SetNeighbor(Block::Face face, Chunk &other) noexcept { neighbor[face] = &other; other.neighbor[Block::Opposite(face)] = this; @@ -246,7 +279,7 @@ int Chunk::GetLight(int index) const noexcept { return light[index]; } -float Chunk::GetVertexLight(const Pos &pos, const BlockModel::Position &vtx, const EntityModel::Normal &norm) const noexcept { +float Chunk::GetVertexLight(const RoughLocation::Fine &pos, const BlockMesh::Position &vtx, const EntityMesh::Normal &norm) const noexcept { int index = ToIndex(pos); float light = GetLight(index); @@ -336,7 +369,21 @@ float Chunk::GetVertexLight(const Pos &pos, const BlockModel::Position &vtx, con } -bool Chunk::IsSurface(const Pos &pos) const noexcept { +glm::vec3 Chunk::GravityAt(const ExactLocation &coords) const noexcept { + glm::vec3 grav(0.0f); + for (int index : gravity) { + RoughLocation::Fine block_pos(ToPos(index)); + ExactLocation block_coords(position, ToCoords(block_pos)); + // trust that block type hasn't changed + grav += Type(index).gravity->GetGravity( + coords.Difference(block_coords).Absolute(), + ToTransform(block_pos, index)); + } + return grav; +} + + +bool Chunk::IsSurface(const RoughLocation::Fine &pos) const noexcept { const Block &block = BlockAt(pos); if (!Type(block).visible) { return false; @@ -353,23 +400,31 @@ bool Chunk::IsSurface(const Pos &pos) const noexcept { bool Chunk::Intersection( const Ray &ray, - const glm::mat4 &M, + const ExactLocation::Coarse &reference, WorldCollision &coll ) noexcept { int idx = 0; coll.chunk = this; coll.block = -1; coll.depth = std::numeric_limits::infinity(); - for (int z = 0; z < depth; ++z) { - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x, ++idx) { + for (int z = 0; z < side; ++z) { + for (int y = 0; y < side; ++y) { + for (int x = 0; x < side; ++x, ++idx) { const BlockType &type = Type(idx); - if (!type.visible) { + if (!type.collision || !type.shape) { + continue; + } + RoughLocation::Fine pos(x, y, z); + + // center of the blok relative to the ray + glm::vec3 relative_center(glm::vec3((position - reference) * ExactLocation::Extent() + pos) + 0.5f); + if (ray.DistanceSquared(relative_center) > 3.0f) { continue; } + float cur_dist; glm::vec3 cur_norm; - if (type.shape->Intersects(ray, M * ToTransform(Pos(x, y, z), idx), cur_dist, cur_norm)) { + if (type.shape->Intersects(ray, ToTransform(reference, pos, idx), cur_dist, cur_norm)) { if (cur_dist < coll.depth) { coll.block = idx; coll.depth = cur_dist; @@ -401,14 +456,82 @@ bool Chunk::Intersection( 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) { + + // box's origin relative to the chunk + const glm::vec3 box_coords(Mbox[3] - Mchunk[3]); + const float box_rad = box.OriginRadius(); + + // assume a bounding radius of 2 for blocks + constexpr float block_rad = 2.0f; + const float bb_radius = box_rad + block_rad; + + const RoughLocation::Fine begin(glm::max( + RoughLocation::Fine(0), + RoughLocation::Fine(glm::floor(box_coords - bb_radius)) + )); + const RoughLocation::Fine end(glm::min( + RoughLocation::Fine(side - 1), + RoughLocation::Fine(glm::ceil(box_coords + bb_radius)) + ) - 1); + + for (RoughLocation::Fine pos(begin); pos.z < end.y; ++pos.z) { + for (pos.y = begin.y; pos.y < end.y; ++pos.y) { + for (pos.x = begin.x; pos.x < end.x; ++pos.x) { + int idx = ToIndex(pos); + const BlockType &type = Type(idx); + if (!type.collision || !type.shape) { + continue; + } + if (type.shape->Intersects(Mchunk * ToTransform(pos, idx), box, Mbox, penetration, normal)) { + col.emplace_back(this, idx, penetration, normal); + any = true; + } + } + } + } + return any; +} + +bool Chunk::Intersection( + const Entity &entity, + const glm::mat4 &Mentity, + const glm::mat4 &Mchunk, + std::vector &col +) noexcept { + // entity's origin relative to the chunk + const glm::vec3 entity_coords(Mentity[3] - Mchunk[3]); + const float ec_radius = entity.Radius() + Radius(); + + if (glm::distance2(entity_coords, Center()) > ec_radius * ec_radius) { + return false; + } + + bool any = false; + float penetration; + glm::vec3 normal; + + // assume a bounding radius of 2 for blocks + constexpr float block_rad = 2.0f; + const float eb_radius = entity.Radius() + block_rad; + + const RoughLocation::Fine begin(glm::max( + RoughLocation::Fine(0), + RoughLocation::Fine(glm::floor(entity_coords - eb_radius)) + )); + const RoughLocation::Fine end(glm::min( + RoughLocation::Fine(side), + RoughLocation::Fine(glm::ceil(entity_coords + eb_radius)) + )); + + for (RoughLocation::Fine pos(begin); pos.z < end.z; ++pos.z) { + for (pos.y = begin.y; pos.y < end.y; ++pos.y) { + for (pos.x = begin.x; pos.x < end.x; ++pos.x) { + int idx = ToIndex(pos); const BlockType &type = Type(idx); - if (!type.collision) { + if (!type.collision || !type.shape) { continue; } - if (type.shape->Intersects(Mchunk * ToTransform(Pos(x, y, z), idx), box, Mbox, penetration, normal)) { + if (type.shape->Intersects(Mchunk * ToTransform(pos, idx), entity.Bounds(), Mentity, penetration, normal)) { col.emplace_back(this, idx, penetration, normal); any = true; } @@ -421,50 +544,54 @@ bool Chunk::Intersection( namespace { -BlockModel::Buffer buf; +BlockMesh::Buffer buf; } -void Chunk::Update(BlockModel &model) noexcept { +void Chunk::Update(BlockMesh &model) noexcept { 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(); + const BlockType &type = Type(block); + if (type.visible && type.shape) { + vtx_count += type.shape->VertexCount(); + idx_count += type.shape->IndexCount(); + } } buf.Clear(); buf.Reserve(vtx_count, idx_count); - int idx = 0; - BlockModel::Index vtx_counter = 0; - for (size_t z = 0; z < depth; ++z) { - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x, ++idx) { - const BlockType &type = Type(BlockAt(idx)); - const Pos pos(x, y, z); - - if (!type.visible || Obstructed(pos).All()) continue; - - type.FillBlockModel(buf, ToTransform(pos, idx), vtx_counter); - size_t vtx_begin = vtx_counter; - vtx_counter += type.shape->VertexCount(); - - for (size_t vtx = vtx_begin; vtx < vtx_counter; ++vtx) { - buf.lights.emplace_back(GetVertexLight( - pos, - buf.vertices[vtx], - type.shape->VertexNormal(vtx - vtx_begin, BlockAt(idx).Transform()) - )); + if (idx_count > 0) { + int idx = 0; + BlockMesh::Index vtx_counter = 0; + for (size_t z = 0; z < side; ++z) { + for (size_t y = 0; y < side; ++y) { + for (size_t x = 0; x < side; ++x, ++idx) { + const BlockType &type = Type(BlockAt(idx)); + const RoughLocation::Fine pos(x, y, z); + + if (!type.visible || !type.shape || Obstructed(pos).All()) continue; + + type.FillBlockMesh(buf, ToTransform(pos, idx), vtx_counter); + size_t vtx_begin = vtx_counter; + vtx_counter += type.shape->VertexCount(); + + for (size_t vtx = vtx_begin; vtx < vtx_counter; ++vtx) { + buf.lights.emplace_back(GetVertexLight( + pos, + buf.vertices[vtx], + type.shape->VertexNormal(vtx - vtx_begin, BlockAt(idx).Transform()) + )); + } } } } } model.Update(buf); - ClearModel(); + ClearMesh(); } -Block::FaceSet Chunk::Obstructed(const Pos &pos) const noexcept { +Block::FaceSet Chunk::Obstructed(const RoughLocation::Fine &pos) const noexcept { Block::FaceSet result; for (int f = 0; f < Block::FACE_COUNT; ++f) { @@ -478,17 +605,21 @@ Block::FaceSet Chunk::Obstructed(const Pos &pos) const noexcept { return result; } -glm::mat4 Chunk::ToTransform(const Pos &pos, int idx) const noexcept { +glm::mat4 Chunk::ToTransform(const RoughLocation::Fine &pos, int idx) const noexcept { return glm::translate(ToCoords(pos)) * BlockAt(idx).Transform(); } +glm::mat4 Chunk::ToTransform(const ExactLocation::Coarse &ref, const RoughLocation::Fine &pos, int idx) const noexcept { + return glm::translate(ExactLocation::Fine((position - ref) * ExactLocation::Extent()) + ToCoords(pos)) * BlockAt(idx).Transform(); +} + -BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept +BlockLookup::BlockLookup(Chunk *c, const RoughLocation::Fine &p) noexcept : chunk(c), pos(p) { - while (pos.x >= Chunk::width) { + while (pos.x >= Chunk::side) { if (chunk->HasNeighbor(Block::FACE_RIGHT)) { chunk = &chunk->GetNeighbor(Block::FACE_RIGHT); - pos.x -= Chunk::width; + pos.x -= Chunk::side; } else { chunk = nullptr; return; @@ -497,16 +628,16 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept while (pos.x < 0) { if (chunk->HasNeighbor(Block::FACE_LEFT)) { chunk = &chunk->GetNeighbor(Block::FACE_LEFT); - pos.x += Chunk::width; + pos.x += Chunk::side; } else { chunk = nullptr; return; } } - while (pos.y >= Chunk::height) { + while (pos.y >= Chunk::side) { if (chunk->HasNeighbor(Block::FACE_UP)) { chunk = &chunk->GetNeighbor(Block::FACE_UP); - pos.y -= Chunk::height; + pos.y -= Chunk::side; } else { chunk = nullptr; return; @@ -515,16 +646,16 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept while (pos.y < 0) { if (chunk->HasNeighbor(Block::FACE_DOWN)) { chunk = &chunk->GetNeighbor(Block::FACE_DOWN); - pos.y += Chunk::height; + pos.y += Chunk::side; } else { chunk = nullptr; return; } } - while (pos.z >= Chunk::depth) { + while (pos.z >= Chunk::side) { if (chunk->HasNeighbor(Block::FACE_FRONT)) { chunk = &chunk->GetNeighbor(Block::FACE_FRONT); - pos.z -= Chunk::depth; + pos.z -= Chunk::side; } else { chunk = nullptr; return; @@ -533,7 +664,7 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept while (pos.z < 0) { if (chunk->HasNeighbor(Block::FACE_BACK)) { chunk = &chunk->GetNeighbor(Block::FACE_BACK); - pos.z += Chunk::depth; + pos.z += Chunk::side; } else { chunk = nullptr; return; @@ -541,11 +672,11 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept } } -BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face face) noexcept +BlockLookup::BlockLookup(Chunk *c, const RoughLocation::Fine &p, Block::Face face) noexcept : chunk(c), pos(p) { pos += Block::FaceNormal(face); if (!Chunk::InBounds(pos)) { - pos -= Block::FaceNormal(face) * Chunk::Extent(); + pos -= Block::FaceNormal(face) * ExactLocation::Extent(); chunk = &chunk->GetNeighbor(face); } } @@ -598,7 +729,7 @@ int ChunkLoader::ToLoad() const noexcept { bool ChunkLoader::LoadOne() { if (!store.HasMissing()) return false; - Chunk::Pos pos = store.NextMissing(); + ExactLocation::Coarse pos = store.NextMissing(); Chunk *chunk = store.Allocate(pos); if (!chunk) { // chunk store corrupted? @@ -618,16 +749,20 @@ bool ChunkLoader::LoadOne() { return generated; } - Chunk::Pos begin(pos - Chunk::Pos(1)); - Chunk::Pos end(pos + Chunk::Pos(2)); - for (Chunk::Pos iter(begin); iter.z < end.z; ++iter.z) { + ExactLocation::Coarse begin(pos - ExactLocation::Coarse(1)); + ExactLocation::Coarse end(pos + ExactLocation::Coarse(2)); + for (ExactLocation::Coarse iter(begin); iter.z < end.z; ++iter.z) { for (iter.y = begin.y; iter.y < end.y; ++iter.y) { for (iter.x = begin.x; iter.x < end.x; ++iter.x) { if (index->IsBorder(iter)) continue; Chunk *light_chunk = index->Get(iter); - if (!light_chunk || light_chunk->Lighted()) continue; + if (!light_chunk) continue; if (index->HasAllSurrounding(iter)) { - light_chunk->ScanLights(); + if (!light_chunk->Lighted()) { + light_chunk->ScanLights(); + } else { + light_chunk->InvalidateMesh(); + } } } } @@ -660,7 +795,7 @@ int ChunkRenderer::MissingChunks() const noexcept { return index.MissingChunks(); } -void ChunkRenderer::LoadTextures(const AssetLoader &loader, const TextureIndex &tex_index) { +void ChunkRenderer::LoadTextures(const AssetLoader &loader, const ResourceIndex &tex_index) { block_tex.Bind(); loader.LoadTextures(tex_index, block_tex); block_tex.FilterNearest(); @@ -668,7 +803,11 @@ void ChunkRenderer::LoadTextures(const AssetLoader &loader, const TextureIndex & void ChunkRenderer::Update(int dt) { for (int i = 0, updates = 0; updates < dt && i < index.TotalChunks(); ++i) { - if (index[i] && index[i]->ShouldUpdateModel()) { + if (!index[i]) continue; + if (!index[i]->Lighted() && index.HasAllSurrounding(index[i]->Position())) { + index[i]->ScanLights(); + } + if (index[i]->ShouldUpdateMesh()) { index[i]->Update(models[i]); ++updates; } @@ -680,22 +819,28 @@ void ChunkRenderer::Render(Viewport &viewport) { chunk_prog.SetTexture(block_tex); chunk_prog.SetFogDensity(fog_density); + Frustum frustum(glm::transpose(chunk_prog.GetVP())); + AABB box; + for (int i = 0; i < index.TotalChunks(); ++i) { if (!index[i]) continue; - glm::mat4 m(index[i]->Transform(index.Base())); - glm::mat4 mvp(chunk_prog.GetVP() * m); - if (!CullTest(Chunk::Bounds(), mvp)) { - if (index[i]->ShouldUpdateModel()) { + box.min = (index[i]->Position() - index.Base()) * ExactLocation::Extent(); + box.max = box.min + ExactLocation::FExtent(); + + if (!CullTest(box, frustum)) { + if (index[i]->ShouldUpdateMesh()) { index[i]->Update(models[i]); } - chunk_prog.SetM(m); - models[i].Draw(); + if (!models[i].Empty()) { + chunk_prog.SetM(index[i]->Transform(index.Base())); + models[i].Draw(); + } } } } -ChunkIndex::ChunkIndex(ChunkStore &store, const Chunk::Pos &base, int extent) +ChunkIndex::ChunkIndex(ChunkStore &store, const ExactLocation::Coarse &base, int extent) : store(store) , base(base) , extent(extent) @@ -712,22 +857,22 @@ ChunkIndex::~ChunkIndex() { Clear(); } -bool ChunkIndex::InRange(const Chunk::Pos &pos) const noexcept { +bool ChunkIndex::InRange(const ExactLocation::Coarse &pos) const noexcept { return Distance(pos) <= extent; } -bool ChunkIndex::IsBorder(const Chunk::Pos &pos) const noexcept { +bool ChunkIndex::IsBorder(const ExactLocation::Coarse &pos) const noexcept { return Distance(pos) == extent; } -int ChunkIndex::Distance(const Chunk::Pos &pos) const noexcept { +int ChunkIndex::Distance(const ExactLocation::Coarse &pos) const noexcept { return manhattan_radius(pos - base); } -bool ChunkIndex::HasAllSurrounding(const Chunk::Pos &pos) const noexcept { - Chunk::Pos begin(pos - Chunk::Pos(1)); - Chunk::Pos end(pos + Chunk::Pos(2)); - for (Chunk::Pos iter(begin); iter.z < end.z; ++iter.z) { +bool ChunkIndex::HasAllSurrounding(const ExactLocation::Coarse &pos) const noexcept { + ExactLocation::Coarse begin(pos - ExactLocation::Coarse(1)); + ExactLocation::Coarse end(pos + ExactLocation::Coarse(2)); + for (ExactLocation::Coarse iter(begin); iter.z < end.z; ++iter.z) { for (iter.y = begin.y; iter.y < end.y; ++iter.y) { for (iter.x = begin.x; iter.x < end.x; ++iter.x) { if (!Get(iter)) return false; @@ -737,8 +882,8 @@ bool ChunkIndex::HasAllSurrounding(const Chunk::Pos &pos) const noexcept { return true; } -int ChunkIndex::IndexOf(const Chunk::Pos &pos) const noexcept { - Chunk::Pos mod_pos( +int ChunkIndex::IndexOf(const ExactLocation::Coarse &pos) const noexcept { + ExactLocation::Coarse mod_pos( GetCol(pos.x), GetCol(pos.y), GetCol(pos.z) @@ -748,18 +893,18 @@ int ChunkIndex::IndexOf(const Chunk::Pos &pos) const noexcept { + mod_pos.z * stride.z; } -Chunk::Pos ChunkIndex::PositionOf(int i) const noexcept { - Chunk::Pos zero_pos( +ExactLocation::Coarse ChunkIndex::PositionOf(int i) const noexcept { + ExactLocation::Coarse zero_pos( (i / stride.x) % side_length, (i / stride.y) % side_length, (i / stride.z) % side_length ); - Chunk::Pos zero_base( + ExactLocation::Coarse zero_base( GetCol(base.x), GetCol(base.y), GetCol(base.z) ); - Chunk::Pos base_relative(zero_pos - zero_base); + ExactLocation::Coarse base_relative(zero_pos - zero_base); if (base_relative.x > extent) base_relative.x -= side_length; else if (base_relative.x < -extent) base_relative.x += side_length; if (base_relative.y > extent) base_relative.y -= side_length; @@ -769,7 +914,7 @@ Chunk::Pos ChunkIndex::PositionOf(int i) const noexcept { return base + base_relative; } -Chunk *ChunkIndex::Get(const Chunk::Pos &pos) noexcept { +Chunk *ChunkIndex::Get(const ExactLocation::Coarse &pos) noexcept { if (InRange(pos)) { return chunks[IndexOf(pos)]; } else { @@ -777,7 +922,7 @@ Chunk *ChunkIndex::Get(const Chunk::Pos &pos) noexcept { } } -const Chunk *ChunkIndex::Get(const Chunk::Pos &pos) const noexcept { +const Chunk *ChunkIndex::Get(const ExactLocation::Coarse &pos) const noexcept { if (InRange(pos)) { return chunks[IndexOf(pos)]; } else { @@ -785,10 +930,10 @@ const Chunk *ChunkIndex::Get(const Chunk::Pos &pos) const noexcept { } } -void ChunkIndex::Rebase(const Chunk::Pos &new_base) { +void ChunkIndex::Rebase(const ExactLocation::Coarse &new_base) { if (new_base == base) return; - Chunk::Pos diff(new_base - base); + ExactLocation::Coarse diff(new_base - base); if (manhattan_radius(diff) > extent) { // that's more than half, so probably not worth shifting @@ -887,7 +1032,7 @@ void ChunkIndex::Unset(int index) noexcept { } } -Chunk::Pos ChunkIndex::NextMissing() noexcept { +ExactLocation::Coarse ChunkIndex::NextMissing() noexcept { if (MissingChunks() > 0) { int roundtrip = last_missing; last_missing = (last_missing + 1) % total_length; @@ -914,7 +1059,7 @@ ChunkStore::~ChunkStore() { } -ChunkIndex &ChunkStore::MakeIndex(const Chunk::Pos &pos, int extent) { +ChunkIndex &ChunkStore::MakeIndex(const ExactLocation::Coarse &pos, int extent) { indices.emplace_back(*this, pos, extent); return indices.back(); } @@ -930,7 +1075,7 @@ void ChunkStore::UnregisterIndex(ChunkIndex &index) { } } -ChunkIndex *ChunkStore::ClosestIndex(const Chunk::Pos &pos) { +ChunkIndex *ChunkStore::ClosestIndex(const ExactLocation::Coarse &pos) { ChunkIndex *closest_index = nullptr; int closest_distance = std::numeric_limits::max(); @@ -945,7 +1090,7 @@ ChunkIndex *ChunkStore::ClosestIndex(const Chunk::Pos &pos) { return closest_index; } -Chunk *ChunkStore::Get(const Chunk::Pos &pos) { +Chunk *ChunkStore::Get(const ExactLocation::Coarse &pos) noexcept { for (ChunkIndex &index : indices) { Chunk *chunk = index.Get(pos); if (chunk) { @@ -955,7 +1100,17 @@ Chunk *ChunkStore::Get(const Chunk::Pos &pos) { return nullptr; } -Chunk *ChunkStore::Allocate(const Chunk::Pos &pos) { +const Chunk *ChunkStore::Get(const ExactLocation::Coarse &pos) const noexcept { + for (const ChunkIndex &index : indices) { + const Chunk *chunk = index.Get(pos); + if (chunk) { + return chunk; + } + } + return nullptr; +} + +Chunk *ChunkStore::Allocate(const ExactLocation::Coarse &pos) { Chunk *chunk = Get(pos); if (chunk) { return chunk; @@ -975,7 +1130,7 @@ Chunk *ChunkStore::Allocate(const Chunk::Pos &pos) { } for (int i = 0; i < Block::FACE_COUNT; ++i) { Block::Face face = Block::Face(i); - Chunk::Pos neighbor_pos(pos + Block::FaceNormal(face)); + ExactLocation::Coarse neighbor_pos(pos + Block::FaceNormal(face)); Chunk *neighbor = Get(neighbor_pos); if (neighbor) { chunk->SetNeighbor(face, *neighbor); @@ -1001,13 +1156,13 @@ int ChunkStore::EstimateMissing() const noexcept { return missing; } -Chunk::Pos ChunkStore::NextMissing() noexcept { +ExactLocation::Coarse ChunkStore::NextMissing() noexcept { for (ChunkIndex &index : indices) { if (index.MissingChunks()) { return index.NextMissing(); } } - return Chunk::Pos(0, 0, 0); + return ExactLocation::Coarse(0, 0, 0); } void ChunkStore::Clean() { @@ -1019,7 +1174,7 @@ void ChunkStore::Clean() { ++i; free.splice(free.end(), loaded, chunk); chunk->Unlink(); - chunk->InvalidateModel(); + chunk->InvalidateMesh(); } } }