X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fchunk.cpp;h=3824a471ac321936bb8c794bc560105cef282525;hb=e53a0e2e711a7d8bd9b0ddacd1360aa14370643f;hp=5162952347b492c8578bf28da291555a37059533;hpb=38abfe4f5342f20b56052ac3090694eabf028d16;p=blank.git diff --git a/src/chunk.cpp b/src/chunk.cpp index 5162952..3824a47 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -2,43 +2,45 @@ #include "generator.hpp" +#include #include #include -#include namespace blank { -Chunk::Chunk(const BlockTypeRegistry &types) +constexpr int Chunk::width; +constexpr int Chunk::height; +constexpr int Chunk::depth; +constexpr int Chunk::size; + + +Chunk::Chunk(const BlockTypeRegistry &types) noexcept : types(&types) -, neighbor{ 0, 0, 0, 0, 0, 0 } -, blocks() -, light() +, neighbor{0} +, blocks{} +, light{0} , model() , position(0, 0, 0) , dirty(false) { } -Chunk::Chunk(Chunk &&other) +Chunk::Chunk(Chunk &&other) noexcept : types(other.types) -, blocks(std::move(other.blocks)) -, light(std::move(other.light)) , model(std::move(other.model)) , position(other.position) , dirty(other.dirty) { - for (size_t i = 0; i < Block::FACE_COUNT; ++i) { - neighbor[i] = other.neighbor[i]; - } + 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); } -Chunk &Chunk::operator =(Chunk &&other) { +Chunk &Chunk::operator =(Chunk &&other) noexcept { types = other.types; - for (size_t i = 0; i < Block::FACE_COUNT; ++i) { - neighbor[i] = other.neighbor[i]; - } - blocks = std::move(other.blocks); - light = std::move(other.light); + 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); model = std::move(other.model); position = other.position; dirty = other.dirty; @@ -56,16 +58,16 @@ struct SetNode { SetNode(Chunk *chunk, Chunk::Pos pos) : chunk(chunk), pos(pos) { } - int Get() const { return chunk->GetLight(pos); } - void Set(int level) { chunk->SetLight(pos, level); } + int Get() const noexcept { return chunk->GetLight(pos); } + void Set(int level) noexcept { chunk->SetLight(pos, level); } - bool HasNext(Block::Face face) { + bool HasNext(Block::Face face) noexcept { const BlockLookup next(chunk, pos, face); - return next.result && !next.chunk->Type(*next.result).block_light; + return next && !next.GetType().block_light; } - SetNode GetNext(Block::Face face) { + SetNode GetNext(Block::Face face) noexcept { const BlockLookup next(chunk, pos, face); - return SetNode(next.chunk, next.pos); + return SetNode(&next.GetChunk(), next.GetBlockPos()); } }; @@ -82,18 +84,18 @@ struct UnsetNode : SetNode(set), level(Get()) { } - bool HasNext(Block::Face face) { + bool HasNext(Block::Face face) noexcept { const BlockLookup next(chunk, pos, face); - return next.result; + return next; } - UnsetNode GetNext(Block::Face face) { return UnsetNode(SetNode::GetNext(face)); } + UnsetNode GetNext(Block::Face face) noexcept { return UnsetNode(SetNode::GetNext(face)); } }; std::queue light_queue; std::queue dark_queue; -void work_light() { +void work_light() noexcept { while (!light_queue.empty()) { SetNode node = light_queue.front(); light_queue.pop(); @@ -111,7 +113,7 @@ void work_light() { } } -void work_dark() { +void work_dark() noexcept { while (!dark_queue.empty()) { UnsetNode node = dark_queue.front(); dark_queue.pop(); @@ -133,7 +135,7 @@ void work_dark() { } -void Chunk::SetBlock(int index, const Block &block) { +void Chunk::SetBlock(int index, const Block &block) noexcept { const BlockType &old_type = Type(blocks[index]); const BlockType &new_type = Type(block); @@ -166,18 +168,9 @@ void Chunk::SetBlock(int index, const Block &block) { // obstacle removed int level = 0; for (int face = 0; face < Block::FACE_COUNT; ++face) { - Pos next_pos(ToPos(index) + Block::FaceNormal(Block::Face(face))); - int next_level = 0; - if (InBounds(next_pos)) { - next_level = GetLight(next_pos); - } else { - if (HasNeighbor(Block::Face(face))) { - next_pos -= (Block::FaceNormal(Block::Face(face)) * Chunk::Extent()); - next_level = GetNeighbor(Block::Face(face)).GetLight(next_pos); - } - } - if (level < next_level) { - level = next_level; + BlockLookup next_block(this, ToPos(index), Block::Face(face)); + if (next_block) { + level = std::min(level, next_block.GetLight()); } } if (level > 1) { @@ -188,26 +181,15 @@ void Chunk::SetBlock(int index, const Block &block) { } } -const Block *Chunk::FindNext(const Pos &pos, Block::Face face) const { - Pos next_pos(pos + Block::FaceNormal(face)); - if (InBounds(next_pos)) { - return &BlockAt(pos + Block::FaceNormal(face)); - } else if (HasNeighbor(face)) { - return &GetNeighbor(face).BlockAt(next_pos - (Block::FaceNormal(face) * Extent())); - } else { - return nullptr; - } -} - -void Chunk::SetNeighbor(Chunk &other) { +void Chunk::SetNeighbor(Chunk &other) noexcept { if (other.position == position + Pos(-1, 0, 0)) { if (neighbor[Block::FACE_LEFT] != &other) { neighbor[Block::FACE_LEFT] = &other; other.neighbor[Block::FACE_RIGHT] = this; - for (int z = 0; z < Depth(); ++z) { - for (int y = 0; y < Height(); ++y) { + for (int z = 0; z < depth; ++z) { + for (int y = 0; y < height; ++y) { Pos my_pos(0, y, z); - Pos other_pos(Width() - 1, y, z); + Pos other_pos(width - 1, y, z); if (GetLight(my_pos) > 0) { light_queue.emplace(this, my_pos); } @@ -222,9 +204,9 @@ void Chunk::SetNeighbor(Chunk &other) { if (neighbor[Block::FACE_RIGHT] != &other) { neighbor[Block::FACE_RIGHT] = &other; other.neighbor[Block::FACE_LEFT] = this; - for (int z = 0; z < Depth(); ++z) { - for (int y = 0; y < Height(); ++y) { - Pos my_pos(Width() - 1, y, z); + for (int z = 0; z < depth; ++z) { + 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); @@ -240,10 +222,10 @@ void Chunk::SetNeighbor(Chunk &other) { if (neighbor[Block::FACE_DOWN] != &other) { neighbor[Block::FACE_DOWN] = &other; other.neighbor[Block::FACE_UP] = this; - for (int z = 0; z < Depth(); ++z) { - for (int x = 0; x < Width(); ++x) { + for (int z = 0; z < depth; ++z) { + for (int x = 0; x < width; ++x) { Pos my_pos(x, 0, z); - Pos other_pos(x, Height() - 1, z); + Pos other_pos(x, height - 1, z); if (GetLight(my_pos) > 0) { light_queue.emplace(this, my_pos); } @@ -258,9 +240,9 @@ void Chunk::SetNeighbor(Chunk &other) { if (neighbor[Block::FACE_UP] != &other) { neighbor[Block::FACE_UP] = &other; other.neighbor[Block::FACE_DOWN] = this; - for (int z = 0; z < Depth(); ++z) { - for (int x = 0; x < Width(); ++x) { - Pos my_pos(x, Height() - 1, z); + for (int z = 0; z < depth; ++z) { + 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); @@ -276,10 +258,10 @@ void Chunk::SetNeighbor(Chunk &other) { if (neighbor[Block::FACE_BACK] != &other) { neighbor[Block::FACE_BACK] = &other; other.neighbor[Block::FACE_FRONT] = this; - for (int y = 0; y < Height(); ++y) { - for (int x = 0; x < Width(); ++x) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { Pos my_pos(x, y, 0); - Pos other_pos(x, y, Depth() - 1); + Pos other_pos(x, y, depth - 1); if (GetLight(my_pos) > 0) { light_queue.emplace(this, my_pos); } @@ -294,9 +276,9 @@ void Chunk::SetNeighbor(Chunk &other) { if (neighbor[Block::FACE_FRONT] != &other) { neighbor[Block::FACE_FRONT] = &other; other.neighbor[Block::FACE_BACK] = this; - for (int y = 0; y < Height(); ++y) { - for (int x = 0; x < Width(); ++x) { - Pos my_pos(x, y, Depth() - 1); + for (int y = 0; y < height; ++y) { + 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); @@ -311,110 +293,138 @@ void Chunk::SetNeighbor(Chunk &other) { } } -void Chunk::ClearNeighbors() { +void Chunk::ClearNeighbors() noexcept { for (int i = 0; i < Block::FACE_COUNT; ++i) { neighbor[i] = nullptr; } } -void Chunk::Unlink() { - if (neighbor[Block::FACE_UP]) { - neighbor[Block::FACE_UP]->neighbor[Block::FACE_DOWN] = nullptr; - } - if (neighbor[Block::FACE_DOWN]) { - neighbor[Block::FACE_DOWN]->neighbor[Block::FACE_UP] = nullptr; - } - if (neighbor[Block::FACE_LEFT]) { - neighbor[Block::FACE_LEFT]->neighbor[Block::FACE_RIGHT] = nullptr; - } - if (neighbor[Block::FACE_RIGHT]) { - neighbor[Block::FACE_RIGHT]->neighbor[Block::FACE_LEFT] = nullptr; - } - if (neighbor[Block::FACE_FRONT]) { - neighbor[Block::FACE_FRONT]->neighbor[Block::FACE_BACK] = nullptr; - } - if (neighbor[Block::FACE_BACK]) { - neighbor[Block::FACE_BACK]->neighbor[Block::FACE_FRONT] = 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() { - if (neighbor[Block::FACE_UP]) { - neighbor[Block::FACE_UP]->neighbor[Block::FACE_DOWN] = this; - } - if (neighbor[Block::FACE_DOWN]) { - neighbor[Block::FACE_DOWN]->neighbor[Block::FACE_UP] = this; - } - if (neighbor[Block::FACE_LEFT]) { - neighbor[Block::FACE_LEFT]->neighbor[Block::FACE_RIGHT] = this; - } - if (neighbor[Block::FACE_RIGHT]) { - neighbor[Block::FACE_RIGHT]->neighbor[Block::FACE_LEFT] = this; - } - if (neighbor[Block::FACE_FRONT]) { - neighbor[Block::FACE_FRONT]->neighbor[Block::FACE_BACK] = this; - } - if (neighbor[Block::FACE_BACK]) { - neighbor[Block::FACE_BACK]->neighbor[Block::FACE_FRONT] = this; +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; + } } } -void Chunk::SetLight(int index, int level) { +void Chunk::SetLight(int index, int level) noexcept { if (light[index] != level) { light[index] = level; Invalidate(); } } -int Chunk::GetLight(int index) const { +int Chunk::GetLight(int index) const noexcept { return light[index]; } -float Chunk::GetVertexLight(int index, const BlockModel::Position &vtx, const BlockModel::Normal &norm) const { +float Chunk::GetVertexLight(const Pos &pos, const BlockModel::Position &vtx, const Model::Normal &norm) const noexcept { + int index = ToIndex(pos); float light = GetLight(index); - Chunk::Pos pos(ToPos(index)); Block::Face direct_face(Block::NormalFace(norm)); - const Chunk *direct_chunk = this; - Chunk::Pos direct_pos(pos + Block::FaceNormal(direct_face)); - if (!InBounds(direct_pos)) { - if (HasNeighbor(direct_face)) { - direct_chunk = &GetNeighbor(direct_face); - direct_pos -= (Block::FaceNormal(direct_face) * Extent()); - float direct_light = direct_chunk->GetLight(direct_pos); - if (direct_light > light) { - light = direct_light; - } - } - } else { - float direct_light = direct_chunk->GetLight(direct_pos); + // tis okay + BlockLookup direct(const_cast(this), pos, Block::NormalFace(norm)); + if (direct) { + float direct_light = direct.GetLight(); if (direct_light > light) { light = direct_light; } + } else { + return light; } - // cheap alternative until AO etc are implemented - // to tell the faces apart + if (Type(BlockAt(index)).luminosity > 0 || direct.GetType().block_light) { + return light; + } + + Block::Face edge[2]; + switch (Block::Axis(direct_face)) { + case 0: // X + edge[0] = (vtx.y - pos.y) > 0.5f ? Block::FACE_UP : Block::FACE_DOWN; + edge[1] = (vtx.z - pos.z) > 0.5f ? Block::FACE_FRONT : Block::FACE_BACK; + break; + case 1: // Y + edge[0] = (vtx.z - pos.z) > 0.5f ? Block::FACE_FRONT : Block::FACE_BACK; + edge[1] = (vtx.x - pos.x) > 0.5f ? Block::FACE_RIGHT : Block::FACE_LEFT; + break; + case 2: // Z + edge[0] = (vtx.x - pos.x) > 0.5f ? Block::FACE_RIGHT : Block::FACE_LEFT; + edge[1] = (vtx.y - pos.y) > 0.5f ? Block::FACE_UP : Block::FACE_DOWN; + break; + } + + int num = 1; + int occlusion = 0; - if (direct_face == Block::FACE_LEFT || direct_face == Block::FACE_RIGHT) { - light -= 0.2; - } else if (direct_face == Block::FACE_FRONT || direct_face == Block::FACE_BACK) { - light -= 0.4; + BlockLookup next[2] = { + direct.Next(edge[0]), + direct.Next(edge[1]), + }; + + if (next[0]) { + if (next[0].GetType().block_light) { + ++occlusion; + } else { + light += next[0].GetLight(); + ++num; + } + } + if (next[1]) { + if (next[1].GetType().block_light) { + ++occlusion; + } else { + light += next[1].GetLight(); + ++num; + } + } + if (occlusion < 2) { + if (next[0]) { + BlockLookup corner = next[0].Next(edge[1]); + if (corner) { + if (corner.GetType().block_light) { + ++occlusion; + } else { + light += corner.GetLight(); + ++num; + } + } + } else if (next[1]) { + BlockLookup corner = next[1].Next(edge[0]); + if (corner) { + if (corner.GetType().block_light) { + ++occlusion; + } else { + light += corner.GetLight(); + ++num; + } + } + } + } else { + ++occlusion; } - return light; + return (light / num) - (occlusion * 0.8f); } -bool Chunk::IsSurface(const Pos &pos) const { +bool Chunk::IsSurface(const Pos &pos) const noexcept { const Block &block = BlockAt(pos); if (!Type(block).visible) { return false; } for (int face = 0; face < Block::FACE_COUNT; ++face) { - const Block *next = FindNext(pos, Block::Face(face)); - if (!next || !Type(*next).visible) { + BlockLookup next = BlockLookup(const_cast(this), pos, Block::Face(face)); + if (!next || !next.GetType().visible) { return true; } } @@ -422,13 +432,7 @@ bool Chunk::IsSurface(const Pos &pos) const { } -void Chunk::Allocate() { - blocks.resize(Size(), Block(0)); - light.resize(Size(), 0); -} - - -void Chunk::Draw() { +void Chunk::Draw() noexcept { if (dirty) { Update(); } @@ -442,22 +446,23 @@ bool Chunk::Intersection( int &blkid, float &dist, glm::vec3 &normal -) const { +) const noexcept { // TODO: should be possible to heavily optimize this - int id = 0; + int idx = 0; blkid = -1; dist = 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, ++id) { - if (!Type(blocks[id]).visible) { + for (int 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.visible) { continue; } float cur_dist; glm::vec3 cur_norm; - if (Type(blocks[id]).shape->Intersects(ray, M * ToTransform(id), cur_dist, cur_norm)) { + if (type.shape->Intersects(ray, M * ToTransform(Pos(x, y, z), idx), cur_dist, cur_norm)) { if (cur_dist < dist) { - blkid = id; + blkid = idx; dist = cur_dist; normal = cur_norm; } @@ -474,14 +479,6 @@ bool Chunk::Intersection( } } -void Chunk::Position(const Pos &pos) { - position = pos; -} - -glm::mat4 Chunk::Transform(const Pos &offset) const { - return glm::translate((position - offset) * Extent()); -} - namespace { @@ -489,13 +486,13 @@ BlockModel::Buffer buf; } -void Chunk::CheckUpdate() { +void Chunk::CheckUpdate() noexcept { if (dirty) { Update(); } } -void Chunk::Update() { +void Chunk::Update() noexcept { int vtx_count = 0, idx_count = 0; for (const auto &block : blocks) { const Shape *shape = Type(block).shape; @@ -505,18 +502,28 @@ void Chunk::Update() { buf.Clear(); buf.Reserve(vtx_count, idx_count); + int idx = 0; BlockModel::Index vtx_counter = 0; - for (size_t i = 0; i < Size(); ++i) { - const BlockType &type = Type(blocks[i]); - - if (!type.visible || Obstructed(i)) continue; - - type.FillBlockModel(buf, ToTransform(i), 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(i, buf.vertices[vtx], buf.normals[vtx])); + 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()) + )); + } + } } } @@ -524,170 +531,94 @@ void Chunk::Update() { dirty = false; } -bool Chunk::Obstructed(int idx) const { - Chunk::Pos pos(ToPos(idx)); - - Chunk::Pos left_pos(pos + Chunk::Pos(-1, 0, 0)); - const Block *left_block = nullptr; - if (InBounds(left_pos)) { - left_block = &BlockAt(left_pos); - } else if (HasNeighbor(Block::FACE_LEFT)) { - left_pos += Chunk::Pos(Width(), 0, 0); - left_block = &GetNeighbor(Block::FACE_LEFT).BlockAt(left_pos); - } else { - return false; - } - if (!Type(*left_block).FaceFilled(*left_block, Block::FACE_RIGHT)) { - return false; - } - - Chunk::Pos right_pos(pos + Chunk::Pos(1, 0, 0)); - const Block *right_block = nullptr; - if (InBounds(right_pos)) { - right_block = &BlockAt(right_pos); - } else if (HasNeighbor(Block::FACE_RIGHT)) { - right_pos += Chunk::Pos(-Width(), 0, 0); - right_block = &GetNeighbor(Block::FACE_RIGHT).BlockAt(right_pos); - } else { - return false; - } - if (!Type(*right_block).FaceFilled(*right_block, Block::FACE_LEFT)) { - return false; - } - - Chunk::Pos down_pos(pos + Chunk::Pos(0, -1, 0)); - const Block *down_block = nullptr; - if (InBounds(down_pos)) { - down_block = &BlockAt(down_pos); - } else if (HasNeighbor(Block::FACE_DOWN)) { - down_pos += Chunk::Pos(0, Height(), 0); - down_block = &GetNeighbor(Block::FACE_DOWN).BlockAt(down_pos); - } else { - return false; - } - if (!Type(*down_block).FaceFilled(*down_block, Block::FACE_UP)) { - return false; - } +Block::FaceSet Chunk::Obstructed(const Pos &pos) const noexcept { + Block::FaceSet result; - Chunk::Pos up_pos(pos + Chunk::Pos(0, 1, 0)); - const Block *up_block = nullptr; - if (InBounds(up_pos)) { - up_block = &BlockAt(up_pos); - } else if (HasNeighbor(Block::FACE_UP)) { - up_pos += Chunk::Pos(0, -Height(), 0); - up_block = &GetNeighbor(Block::FACE_UP).BlockAt(up_pos); - } else { - return false; - } - if (!Type(*up_block).FaceFilled(*up_block, Block::FACE_DOWN)) { - return false; - } - - Chunk::Pos back_pos(pos + Chunk::Pos(0, 0, -1)); - const Block *back_block = nullptr; - if (InBounds(back_pos)) { - back_block = &BlockAt(back_pos); - } else if (HasNeighbor(Block::FACE_BACK)) { - back_pos += Chunk::Pos(0, 0, Depth()); - back_block = &GetNeighbor(Block::FACE_BACK).BlockAt(back_pos); - } else { - return false; - } - if (!Type(*back_block).FaceFilled(*back_block, Block::FACE_FRONT)) { - return false; - } - - Chunk::Pos front_pos(pos + Chunk::Pos(0, 0, 1)); - const Block *front_block = nullptr; - if (InBounds(front_pos)) { - front_block = &BlockAt(front_pos); - } else if (HasNeighbor(Block::FACE_FRONT)) { - front_pos += Chunk::Pos(0, 0, -Depth()); - front_block = &GetNeighbor(Block::FACE_FRONT).BlockAt(front_pos); - } else { - return false; - } - if (!Type(*front_block).FaceFilled(*front_block, Block::FACE_BACK)) { - return false; + for (int f = 0; f < Block::FACE_COUNT; ++f) { + Block::Face face = Block::Face(f); + BlockLookup next(const_cast(this), pos, face); + if (next && next.GetType().FaceFilled(next.GetBlock(), Block::Opposite(face))) { + result.Set(face); + } } - return true; + return result; } -glm::mat4 Chunk::ToTransform(int idx) const { - return glm::translate(glm::mat4(1.0f), ToCoords(idx)) * blocks[idx].Transform(); +glm::mat4 Chunk::ToTransform(const Pos &pos, int idx) const noexcept { + return glm::translate(ToCoords(pos)) * BlockAt(idx).Transform(); } -BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) -: chunk(c), pos(p), result(nullptr) { - while (pos.x >= Chunk::Width()) { +BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) noexcept +: chunk(c), pos(p) { + while (pos.x >= Chunk::width) { if (chunk->HasNeighbor(Block::FACE_RIGHT)) { chunk = &chunk->GetNeighbor(Block::FACE_RIGHT); - pos.x -= Chunk::Width(); + pos.x -= Chunk::width; } else { + chunk = nullptr; return; } } while (pos.x < 0) { if (chunk->HasNeighbor(Block::FACE_LEFT)) { chunk = &chunk->GetNeighbor(Block::FACE_LEFT); - pos.x += Chunk::Width(); + pos.x += Chunk::width; } else { + chunk = nullptr; return; } } - while (pos.y >= Chunk::Height()) { + while (pos.y >= Chunk::height) { if (chunk->HasNeighbor(Block::FACE_UP)) { chunk = &chunk->GetNeighbor(Block::FACE_UP); - pos.y -= Chunk::Height(); + pos.y -= Chunk::height; } else { + chunk = nullptr; return; } } while (pos.y < 0) { if (chunk->HasNeighbor(Block::FACE_DOWN)) { chunk = &chunk->GetNeighbor(Block::FACE_DOWN); - pos.y += Chunk::Height(); + pos.y += Chunk::height; } else { + chunk = nullptr; return; } } - while (pos.z >= Chunk::Depth()) { + while (pos.z >= Chunk::depth) { if (chunk->HasNeighbor(Block::FACE_FRONT)) { chunk = &chunk->GetNeighbor(Block::FACE_FRONT); - pos.z -= Chunk::Depth(); + pos.z -= Chunk::depth; } else { + chunk = nullptr; return; } } while (pos.z < 0) { if (chunk->HasNeighbor(Block::FACE_BACK)) { chunk = &chunk->GetNeighbor(Block::FACE_BACK); - pos.z += Chunk::Depth(); + pos.z += Chunk::depth; } else { + chunk = nullptr; return; } } - result = &chunk->BlockAt(pos); } -BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face face) -: chunk(c), pos(p), result(nullptr) { +BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face face) noexcept +: chunk(c), pos(p) { pos += Block::FaceNormal(face); - if (Chunk::InBounds(pos)) { - result = &chunk->BlockAt(pos); - } else { + if (!Chunk::InBounds(pos)) { pos -= Block::FaceNormal(face) * Chunk::Extent(); - if (chunk->HasNeighbor(face)) { - chunk = &chunk->GetNeighbor(face); - result = &chunk->BlockAt(pos); - } + chunk = &chunk->GetNeighbor(face); } } -ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry ®, const Generator &gen) +ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry ®, const Generator &gen) noexcept : base(0, 0, 0) , reg(reg) , gen(gen) @@ -703,10 +634,10 @@ namespace { struct ChunkLess { - explicit ChunkLess(const Chunk::Pos &base) + explicit ChunkLess(const Chunk::Pos &base) noexcept : base(base) { } - bool operator ()(const Chunk::Pos &a, const Chunk::Pos &b) const { + bool operator ()(const Chunk::Pos &a, const Chunk::Pos &b) const noexcept { Chunk::Pos da(base - a); Chunk::Pos db(base - b); return @@ -787,23 +718,22 @@ Chunk &ChunkLoader::Generate(const Chunk::Pos &pos) { loaded.emplace_back(reg); Chunk &chunk = loaded.back(); chunk.Position(pos); - chunk.Allocate(); gen(chunk); Insert(chunk); return chunk; } -void ChunkLoader::Insert(Chunk &chunk) { +void ChunkLoader::Insert(Chunk &chunk) noexcept { for (Chunk &other : loaded) { chunk.SetNeighbor(other); } } -void ChunkLoader::Remove(Chunk &chunk) { +void ChunkLoader::Remove(Chunk &chunk) noexcept { chunk.Unlink(); } -Chunk *ChunkLoader::Loaded(const Chunk::Pos &pos) { +Chunk *ChunkLoader::Loaded(const Chunk::Pos &pos) noexcept { for (Chunk &chunk : loaded) { if (chunk.Position() == pos) { return &chunk; @@ -812,7 +742,7 @@ Chunk *ChunkLoader::Loaded(const Chunk::Pos &pos) { return nullptr; } -bool ChunkLoader::Queued(const Chunk::Pos &pos) { +bool ChunkLoader::Queued(const Chunk::Pos &pos) noexcept { for (const Chunk::Pos &chunk : to_generate) { if (chunk == pos) { return true; @@ -821,7 +751,7 @@ bool ChunkLoader::Queued(const Chunk::Pos &pos) { return nullptr; } -bool ChunkLoader::Known(const Chunk::Pos &pos) { +bool ChunkLoader::Known(const Chunk::Pos &pos) noexcept { if (Loaded(pos)) return true; return Queued(pos); } @@ -881,39 +811,31 @@ void ChunkLoader::GenerateSurrounding(const Chunk::Pos &pos) { } void ChunkLoader::Update() { - bool reused = false; - if (!to_generate.empty()) { - Chunk::Pos pos(to_generate.front()); - - 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); - reused = true; - break; - } - } + if (to_generate.empty()) { + return; + } - if (!reused) { - if (to_free.empty()) { - loaded.emplace_back(reg); - } else { - to_free.front().ClearNeighbors(); - loaded.splice(loaded.end(), to_free, to_free.begin()); - reused = true; - } - Chunk &chunk = loaded.back(); - chunk.Position(pos); - chunk.Allocate(); - gen(chunk); - Insert(chunk); + Chunk::Pos pos(to_generate.front()); + to_generate.pop_front(); + + 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); + return; } - to_generate.pop_front(); } - if (!reused && !to_free.empty()) { - to_free.pop_front(); + 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); + Insert(chunk); } }