X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fchunk.cpp;h=a64e184140f503d4d343b26c04207571db0c459e;hb=c899292fd5dee11bee0fafadf051f4204eb4bf2a;hp=cc53e912683cb99e576219709fd2151bf867019a;hpb=d2d3cb877984b97fafb97254f5005cbf4bcf47a6;p=blank.git diff --git a/src/chunk.cpp b/src/chunk.cpp index cc53e91..a64e184 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -2,6 +2,7 @@ #include "generator.hpp" +#include #include #include #include @@ -11,8 +12,9 @@ namespace blank { Chunk::Chunk(const BlockTypeRegistry &types) : types(&types) -, neighbor{ 0, 0, 0, 0, 0, 0 } -, blocks() +, neighbor{0} +, blocks{} +, light{0} , model() , position(0, 0, 0) , dirty(false) { @@ -21,97 +23,26 @@ Chunk::Chunk(const BlockTypeRegistry &types) Chunk::Chunk(Chunk &&other) : types(other.types) -, blocks(std::move(other.blocks)) , 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) { types = other.types; - for (size_t i = 0; i < Block::FACE_COUNT; ++i) { - neighbor[i] = other.neighbor[i]; - } - blocks = std::move(other.blocks); + 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; return *this; } -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 { @@ -126,16 +57,12 @@ struct SetNode { void Set(int level) { chunk->SetLight(pos, level); } bool HasNext(Block::Face face) { - const Block *next = chunk->FindNext(pos, face); - return next && !chunk->Type(*next).block_light; + const BlockLookup next(chunk, pos, face); + return next && !next.GetType().block_light; } SetNode GetNext(Block::Face face) { - Chunk::Pos next_pos(pos + Block::FaceNormal(face)); - if (Chunk::InBounds(next_pos)) { - return SetNode(chunk, next_pos); - } else { - return SetNode(&chunk->GetNeighbor(face), next_pos - (Block::FaceNormal(face) * Chunk::Extent())); - } + const BlockLookup next(chunk, pos, face); + return SetNode(&next.GetChunk(), next.GetBlockPos()); } }; @@ -151,6 +78,11 @@ struct UnsetNode UnsetNode(const SetNode &set) : SetNode(set), level(Get()) { } + + bool HasNext(Block::Face face) { + const BlockLookup next(chunk, pos, face); + return next; + } UnsetNode GetNext(Block::Face face) { return UnsetNode(SetNode::GetNext(face)); } }; @@ -221,10 +153,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; @@ -262,15 +196,204 @@ 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) { - light[index] = level; + if (light[index] != level) { + light[index] = level; + Invalidate(); + } } int Chunk::GetLight(int index) const { return light[index]; } +float Chunk::GetVertexLight(int index, const BlockModel::Position &vtx, const BlockModel::Normal &norm) const { + float light = GetLight(index); + Chunk::Pos pos(ToPos(index)); + + Block::Face direct_face(Block::NormalFace(norm)); + // 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; + } + } + + // cheap alternative until AO etc are implemented + // to tell the faces apart + + 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; + } + + return light; +} + bool Chunk::IsSurface(const Pos &pos) const { const Block &block = BlockAt(pos); @@ -287,12 +410,6 @@ bool Chunk::IsSurface(const Pos &pos) const { } -void Chunk::Allocate() { - blocks.resize(Size(), Block(0)); - light.resize(Size(), 0); -} - - void Chunk::Draw() { if (dirty) { Update(); @@ -350,7 +467,7 @@ glm::mat4 Chunk::Transform(const Pos &offset) const { namespace { -Model::Buffer buf; +BlockModel::Buffer buf; } @@ -370,14 +487,19 @@ void Chunk::Update() { buf.Clear(); buf.Reserve(vtx_count, idx_count); - Model::Index vtx_counter = 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.FillModel(buf, ToTransform(i), vtx_counter); + 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])); + } } model.Update(buf); @@ -479,6 +601,74 @@ glm::mat4 Chunk::ToTransform(int idx) const { } +BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p) +: 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; + } + } + while (pos.x < 0) { + if (chunk->HasNeighbor(Block::FACE_LEFT)) { + chunk = &chunk->GetNeighbor(Block::FACE_LEFT); + pos.x += Chunk::Width(); + } else { + chunk = nullptr; + return; + } + } + while (pos.y >= Chunk::Height()) { + if (chunk->HasNeighbor(Block::FACE_UP)) { + chunk = &chunk->GetNeighbor(Block::FACE_UP); + 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(); + } else { + chunk = nullptr; + return; + } + } + while (pos.z >= Chunk::Depth()) { + if (chunk->HasNeighbor(Block::FACE_FRONT)) { + chunk = &chunk->GetNeighbor(Block::FACE_FRONT); + 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(); + } else { + chunk = nullptr; + return; + } + } +} + +BlockLookup::BlockLookup(Chunk *c, const Chunk::Pos &p, Block::Face face) +: chunk(c), pos(p) { + pos += Block::FaceNormal(face); + if (!Chunk::InBounds(pos)) { + pos -= Block::FaceNormal(face) * Chunk::Extent(); + chunk = &chunk->GetNeighbor(face); + } +} + + ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry ®, const Generator &gen) : base(0, 0, 0) , reg(reg) @@ -522,6 +712,42 @@ void ChunkLoader::Generate(const Chunk::Pos &from, const Chunk::Pos &to) { } else if (pos == base) { Generate(pos); + // light testing + // for (int i = 0; i < 16; ++i) { + // for (int j = 0; j < 16; ++j) { + // loaded.back().SetBlock(Chunk::Pos{ i, j, 0 }, Block(1)); + // loaded.back().SetBlock(Chunk::Pos{ i, j, 15 }, Block(1)); + // loaded.back().SetBlock(Chunk::Pos{ 0, j, i }, Block(1)); + // loaded.back().SetBlock(Chunk::Pos{ 15, j, i }, Block(1)); + // } + // } + // loaded.back().SetBlock(Chunk::Pos{ 1, 0, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 0, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 1, 0, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 0, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 1, 15, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 15, 1 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 1, 15, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 14, 15, 14 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 7, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 7, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 8, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 8, 0 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 7, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 7, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 7, 8, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 8, 8, 15 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 7, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 7, 8 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 8, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 0, 8, 8 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 7, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 7, 8 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 8, 7 }, Block(13)); + // loaded.back().SetBlock(Chunk::Pos{ 15, 8, 8 }, Block(13)); + // loaded.back().Invalidate(); + // loaded.back().CheckUpdate(); + // orientation testing // for (int i = 0; i < Block::FACE_COUNT; ++i) { // for (int j = 0; j < Block::TURN_COUNT; ++j) { @@ -543,8 +769,8 @@ Chunk &ChunkLoader::Generate(const Chunk::Pos &pos) { loaded.emplace_back(reg); Chunk &chunk = loaded.back(); chunk.Position(pos); - Insert(chunk); gen(chunk); + Insert(chunk); return chunk; } @@ -636,38 +862,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); - Insert(chunk); - gen(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); } }