]> git.localhorst.tv Git - blank.git/blobdiff - src/chunk.cpp
optimized block lookup a little
[blank.git] / src / chunk.cpp
index 994d68e41bf4e930d4d55df86379381685e4f4c3..2da66399407670eb9e1dbc3677c3764c1c6a1fd1 100644 (file)
@@ -46,77 +46,6 @@ Chunk &Chunk::operator =(Chunk &&other) {
 }
 
 
-void Chunk::SetNeighbor(Chunk &other) {
-       if (other.position == position + Pos(-1, 0, 0)) {
-               neighbor[Block::FACE_LEFT] = &other;
-               other.neighbor[Block::FACE_RIGHT] = this;
-       } else if (other.position == position + Pos(1, 0, 0)) {
-               neighbor[Block::FACE_RIGHT] = &other;
-               other.neighbor[Block::FACE_LEFT] = this;
-       } else if (other.position == position + Pos(0, -1, 0)) {
-               neighbor[Block::FACE_DOWN] = &other;
-               other.neighbor[Block::FACE_UP] = this;
-       } else if (other.position == position + Pos(0, 1, 0)) {
-               neighbor[Block::FACE_UP] = &other;
-               other.neighbor[Block::FACE_DOWN] = this;
-       } else if (other.position == position + Pos(0, 0, -1)) {
-               neighbor[Block::FACE_BACK] = &other;
-               other.neighbor[Block::FACE_FRONT] = this;
-       } else if (other.position == position + Pos(0, 0, 1)) {
-               neighbor[Block::FACE_FRONT] = &other;
-               other.neighbor[Block::FACE_BACK] = this;
-       }
-}
-
-void Chunk::ClearNeighbors() {
-       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::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;
-       }
-}
-
-
 namespace {
 
 struct SetNode {
@@ -132,11 +61,11 @@ struct SetNode {
 
        bool HasNext(Block::Face face) {
                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) {
                const BlockLookup next(chunk, pos, face);
-               return SetNode(next.chunk, next.pos);
+               return SetNode(&next.GetChunk(), next.GetBlockPos());
        }
 
 };
@@ -155,7 +84,7 @@ struct UnsetNode
 
        bool HasNext(Block::Face face) {
                const BlockLookup next(chunk, pos, face);
-               return next.result;
+               return next;
        }
        UnsetNode GetNext(Block::Face face) { return UnsetNode(SetNode::GetNext(face)); }
 
@@ -227,10 +156,12 @@ void Chunk::SetBlock(int index, const Block &block) {
                work_light();
        } else if (new_type.block_light && !old_type.block_light) {
                // obstacle added
-               dark_queue.emplace(this, ToPos(index));
-               SetLight(index, 0);
-               work_dark();
-               work_light();
+               if (GetLight(index) > 0) {
+                       dark_queue.emplace(this, ToPos(index));
+                       SetLight(index, 0);
+                       work_dark();
+                       work_light();
+               }
        } else if (!new_type.block_light && old_type.block_light) {
                // obstacle removed
                int level = 0;
@@ -268,6 +199,166 @@ const Block *Chunk::FindNext(const Pos &pos, Block::Face face) const {
        }
 }
 
+void Chunk::SetNeighbor(Chunk &other) {
+       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) {
+                                       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);
+                                       }
+                               }
+                       }
+                       work_light();
+               }
+       } else if (other.position == position + Pos(1, 0, 0)) {
+               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);
+                                       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);
+                                       }
+                               }
+                       }
+                       work_light();
+               }
+       } else if (other.position == position + Pos(0, -1, 0)) {
+               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) {
+                                       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);
+                                       }
+                               }
+                       }
+                       work_light();
+               }
+       } else if (other.position == position + Pos(0, 1, 0)) {
+               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);
+                                       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);
+                                       }
+                               }
+                       }
+                       work_light();
+               }
+       } else if (other.position == position + Pos(0, 0, -1)) {
+               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) {
+                                       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);
+                                       }
+                               }
+                       }
+                       work_light();
+               }
+       } else if (other.position == position + Pos(0, 0, 1)) {
+               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);
+                                       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);
+                                       }
+                               }
+                       }
+                       work_light();
+               }
+       }
+}
+
+void Chunk::ClearNeighbors() {
+       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::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::SetLight(int index, int level) {
        if (light[index] != level) {
@@ -285,19 +376,10 @@ float Chunk::GetVertexLight(int index, const BlockModel::Position &vtx, const Bl
        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<Chunk *>(this), pos, Block::NormalFace(norm));
+       if (direct) {
+               float direct_light = direct.GetLight();
                if (direct_light > light) {
                        light = direct_light;
                }
@@ -529,12 +611,13 @@ glm::mat4 Chunk::ToTransform(int idx) const {
 
 
 BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p)
-: chunk(c), pos(p), result(nullptr) {
+: 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();
                } else {
+                       chunk = nullptr;
                        return;
                }
        }
@@ -543,6 +626,7 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p)
                        chunk = &chunk->GetNeighbor(Block::FACE_LEFT);
                        pos.x += Chunk::Width();
                } else {
+                       chunk = nullptr;
                        return;
                }
        }
@@ -551,6 +635,7 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p)
                        chunk = &chunk->GetNeighbor(Block::FACE_UP);
                        pos.y -= Chunk::Height();
                } else {
+                       chunk = nullptr;
                        return;
                }
        }
@@ -559,6 +644,7 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p)
                        chunk = &chunk->GetNeighbor(Block::FACE_DOWN);
                        pos.y += Chunk::Height();
                } else {
+                       chunk = nullptr;
                        return;
                }
        }
@@ -567,6 +653,7 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p)
                        chunk = &chunk->GetNeighbor(Block::FACE_FRONT);
                        pos.z -= Chunk::Depth();
                } else {
+                       chunk = nullptr;
                        return;
                }
        }
@@ -575,23 +662,18 @@ BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p)
                        chunk = &chunk->GetNeighbor(Block::FACE_BACK);
                        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) {
+: 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);
        }
 }
 
@@ -696,8 +778,9 @@ Chunk &ChunkLoader::Generate(const Chunk::Pos &pos) {
        loaded.emplace_back(reg);
        Chunk &chunk = loaded.back();
        chunk.Position(pos);
-       Insert(chunk);
+       chunk.Allocate();
        gen(chunk);
+       Insert(chunk);
        return chunk;
 }
 
@@ -812,8 +895,9 @@ void ChunkLoader::Update() {
                        }
                        Chunk &chunk = loaded.back();
                        chunk.Position(pos);
-                       Insert(chunk);
+                       chunk.Allocate();
                        gen(chunk);
+                       Insert(chunk);
                }
                to_generate.pop_front();
        }