From 0ebbb897dcde55addb5b65d4b2c88d852496cdbd Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Thu, 1 Jun 2023 21:20:19 +0200 Subject: [PATCH 1/3] chunk: handle special cases for getBlocks Returning Block::AIR when chunk is not yet generated (CHUNK_STATE_GENERATED set to false) is also a way to avoid thread-unsafe concurrent access to the IntervalMaps data structure, since CHUNK_STATE_GENERATED is set to false before generating the Chunk and set again to true after generation is complete --- src/chunk.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chunk.cpp b/src/chunk.cpp index 4f98a8d..66feb49 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -19,6 +19,7 @@ namespace Chunk { this->position = pos; this->setState(CHUNK_STATE_EMPTY, true); + this->setBlocks(0, CHUNK_MAX_INDEX, Block::AIR); } Chunk ::~Chunk() @@ -43,6 +44,8 @@ namespace Chunk Block Chunk::getBlock(int x, int y, int z) { + if(x < 0 || y < 0 || z < 0 || x > CHUNK_SIZE -1 || y > CHUNK_SIZE -1 || z > CHUNK_SIZE-1 || + !getState(CHUNK_STATE_GENERATED)) return Block::AIR; return blocks.at(HILBERT_XYZ_ENCODE[x][y][z]); } From f798575cac383ded45cdbe9aa9d5856af86646a9 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Thu, 1 Jun 2023 21:22:52 +0200 Subject: [PATCH 2/3] chunkmanager: add function getBlockAtPos, returns block at world pos Returns Block::NULLBLK only to signal an invalid position --- include/chunkmanager.hpp | 1 + src/chunkmanager.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/chunkmanager.hpp b/include/chunkmanager.hpp index 5c296fa..fbd4ec7 100644 --- a/include/chunkmanager.hpp +++ b/include/chunkmanager.hpp @@ -21,6 +21,7 @@ namespace chunkmanager void destroy(); oneapi::tbb::concurrent_queue& getDeleteVector(); std::array, chunks_volume>& getChunksIndices(); + Block getBlockAtPos(int x, int y, int z); void update(); } diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index 4f9797f..077f52a 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -10,6 +10,7 @@ #include +#include "block.hpp" #include "chunk.hpp" #include "chunkgenerator.hpp" #include "chunkmesher.hpp" @@ -202,4 +203,27 @@ namespace chunkmanager } } } + + Block getBlockAtPos(int x, int y, int z){ + if(x < 0 || y < 0 || z < 0) return Block::NULLBLK; + + int cx = static_cast(x / CHUNK_SIZE); + int cy = static_cast(y / CHUNK_SIZE); + int cz = static_cast(z / CHUNK_SIZE); + + if(cx < 0 || cy < 0 || cz < 0 || cx > 1023 || cy > 1023 || cz > 1023) return Block::NULLBLK; + + //std::cout << "Block at " << x << ", " << y << ", " << z << " is in chunk " << cx << "," << cy << "," << cz << "\n"; + ChunkTable::accessor a; + if(!chunks.find(a, calculateIndex(cx, cy, cz))) return Block::NULLBLK; + else { + int bx = x % CHUNK_SIZE; + int by = y % CHUNK_SIZE; + int bz = z % CHUNK_SIZE; + + Block b = a->second->getBlock(bx, by, bz); + //std::cout << "Block is at " << bx << "," << by << "," << bz << "(" << (int)b << ")\n"; + return b; + } + } }; From 393e5ca9b2ed4818a9cb9e800ce83ba0c7e4eb25 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Thu, 1 Jun 2023 21:23:57 +0200 Subject: [PATCH 3/3] chunkmesher: seamless chunkborders by checking neighbouring chunks --- src/chunkmesher.cpp | 51 +++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/chunkmesher.cpp b/src/chunkmesher.cpp index 000111a..f0fccdb 100755 --- a/src/chunkmesher.cpp +++ b/src/chunkmesher.cpp @@ -1,9 +1,11 @@ +#include "chunkmesher.hpp" + #include #include #include "block.hpp" #include "chunk.hpp" -#include "chunkmesher.hpp" +#include "chunkmanager.hpp" #include "globals.hpp" #include "renderer.hpp" #include "spacefilling.hpp" @@ -93,25 +95,38 @@ void mesh(Chunk::Chunk* chunk) { for (x[u] = 0; x[u] < CHUNK_SIZE; x[u]++) { - Block b1 = (x[dim] >= 0) ? blocks[HILBERT_XYZ_ENCODE[x[0]][x[1]][x[2]]] : Block::NULLBLK; - Block b2 = (x[dim] < CHUNK_SIZE - 1) - ? blocks[HILBERT_XYZ_ENCODE[x[0] + q[0]][x[1] + q[1]][x[2] + q[2]]] - : Block::NULLBLK; + Block b1, b2; + if(x[dim] >= 0) b1 = blocks[HILBERT_XYZ_ENCODE[x[0]][x[1]][x[2]]]; + else{ + int cx = chunk->getPosition().x*CHUNK_SIZE; + int cy = chunk->getPosition().y*CHUNK_SIZE; + int cz = chunk->getPosition().z*CHUNK_SIZE; - // This is the original line taken from rob's code, readapted (replace voxelFace - // with b1 and b2). - // mask[n++] = ((voxelFace != Block::NULLBLK && voxelFace1 != Block::NULLBLK && - // voxelFace.equals(voxelFace1))) ? Block::NULLBLK : backFace ? voxelFace1 : voxelFace; + int bx = cx+x[0]; + int by = cy+x[1]; + int bz = cz+x[2]; - // Additionally checking whether b1 and b2 are AIR or Block::NULLBLK allows face culling, - // thus not rendering faces that cannot be seen - // Removing the control for Block::NULLBLK disables chunk borders, which is - // not always wanted and needs further checking - // This can be surely refactored in something that isn't such a big one-liner - mask[n++] = b1 != Block::NULLBLK && b2 != Block::NULLBLK && b1 == b2 ? Block::NULLBLK - : backFace ? b1 == Block::AIR || b1 == Block::NULLBLK ? b2 : Block::NULLBLK - : b2 == Block::AIR || b2 == Block::NULLBLK ? b1 - : Block::NULLBLK; + b1 = chunkmanager::getBlockAtPos(bx, by, bz); + } + + if(x[dim] < CHUNK_SIZE - 1) b2 = blocks[HILBERT_XYZ_ENCODE[x[0] + q[0]][x[1] + + q[1]][x[2] + q[2]]]; + else{ + int cx = chunk->getPosition().x*CHUNK_SIZE; + int cy = chunk->getPosition().y*CHUNK_SIZE; + int cz = chunk->getPosition().z*CHUNK_SIZE; + + int bx = cx+x[0] + q[0]; + int by = cy+x[1] + q[1]; + int bz = cz+x[2] + q[2]; + + b2 = chunkmanager::getBlockAtPos(bx, by, bz); + } + + // Compute the mask + mask[n++] = b1 != Block::NULLBLK && b2 != Block::NULLBLK && b1 == b2 ? Block::NULLBLK + : backFace ? b1 == Block::AIR ? b2 : Block::NULLBLK + : b2 == Block::AIR ? b1 : Block::NULLBLK; } }