diff --git a/include/camera.hpp b/include/camera.hpp index ca35f42..9460182 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -18,6 +18,10 @@ public: // This matrix needs to be also updated in viewPortCallback whenever it is changed projection = glm::perspective(glm::radians(90.0f), 800.0f / 600.0f, 0.1f, 1200.0f); + + posX = cameraPos.x; + posY = cameraPos.y; + posZ = cameraPos.z; } void update(GLFWwindow *window, float deltaTime) @@ -112,7 +116,7 @@ public: private: - glm::vec3 cameraPos = glm::vec3(256.0, 80.0f, 256.0f); + glm::vec3 cameraPos = glm::vec3(512.0, 80.0f, 512.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 direction = glm::vec3(0.0f); diff --git a/include/chunk.hpp b/include/chunk.hpp index 17f29fb..26a7f86 100644 --- a/include/chunk.hpp +++ b/include/chunk.hpp @@ -20,9 +20,16 @@ #define CHUNK_VOLUME (CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE) #define CHUNK_MAX_INDEX (CHUNK_VOLUME - 1) +// int32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1023). There's actually two spare bits +typedef int32_t chunk_index_t; +typedef int16_t chunk_intcoord_t; + namespace Chunk { + chunk_index_t calculateIndex(chunk_intcoord_t i, chunk_intcoord_t j, chunk_intcoord_t k); + chunk_index_t calculateIndex(glm::vec3 pos); + constexpr uint8_t CHUNK_STATE_GENERATED = 1; constexpr uint8_t CHUNK_STATE_MESHED = 2; constexpr uint8_t CHUNK_STATE_MESH_LOADED = 4; @@ -58,12 +65,15 @@ namespace Chunk public: GLuint VAO{0}, VBO{0}, extentsBuffer{0}, texinfoBuffer{0}, numVertices{0}; std::atomic unload_timer{0}; + chunk_index_t getIndex(){ return this->index; } private: glm::vec3 position{}; IntervalMap blocks{}; std::atomic_uint8_t state{0}; + + chunk_index_t index; }; }; diff --git a/include/chunkmanager.hpp b/include/chunkmanager.hpp index b32a9af..b393760 100644 --- a/include/chunkmanager.hpp +++ b/include/chunkmanager.hpp @@ -19,7 +19,7 @@ namespace chunkmanager { - typedef oneapi::tbb::concurrent_hash_map ChunkTable; + typedef oneapi::tbb::concurrent_hash_map ChunkTable; typedef std::pair ChunkPQEntry; // The comparing function to use struct compare_f { @@ -31,12 +31,11 @@ namespace chunkmanager void init(); void blockpick(bool place); - uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k); void stop(); void destroy(); oneapi::tbb::concurrent_queue& getDeleteVector(); - std::array, chunks_volume>& getChunksIndices(); + std::array, chunks_volume>& getChunksIndices(); Block getBlockAtPos(int x, int y, int z); void update(); } diff --git a/include/controls.hpp b/include/controls.hpp new file mode 100644 index 0000000..490dbbd --- /dev/null +++ b/include/controls.hpp @@ -0,0 +1,14 @@ +#ifndef CONTROLS_H +#define CONTROLS_H + +#include +#include + +#define BLOCKPICK_TIMEOUT 0.15f + +namespace controls{ + void init(); + void update(GLFWwindow* window); +}; + +#endif diff --git a/include/globals.hpp b/include/globals.hpp index 4b9c243..2f7c254 100644 --- a/include/globals.hpp +++ b/include/globals.hpp @@ -13,7 +13,8 @@ #define RENDER_DISTANCE 16 extr Camera theCamera; -constexpr int chunks_volume = static_cast(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE)); +// the cube spans in both directions, to each axis has to be multiplied by 2. 2^3=8 +constexpr int chunks_volume = 8*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE); extr bool wireframe; extr float sines[360]; diff --git a/include/main.hpp b/include/main.hpp index 38ff189..35e69e7 100644 --- a/include/main.hpp +++ b/include/main.hpp @@ -3,6 +3,5 @@ void framebuffer_size_callback(GLFWwindow *, int, int); void mouse_callback(GLFWwindow *window, double xpos, double ypos); -void processInput(GLFWwindow *); #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6775018..d92b576 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.2) project(OpenGLTest) -set(SOURCE_FILES main.cpp chunk.cpp chunkmanager.cpp chunkmesher.cpp chunkgenerator.cpp +set(SOURCE_FILES main.cpp controls.cpp chunk.cpp chunkmanager.cpp chunkmesher.cpp chunkgenerator.cpp debugwindow.cpp renderer.cpp spacefilling.cpp stb_image.cpp utils.cpp OpenSimplexNoise.cpp) add_executable(OpenGLTest ${SOURCE_FILES}) diff --git a/src/chunk.cpp b/src/chunk.cpp index b14fffc..982edf8 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -15,11 +15,21 @@ namespace Chunk return utils::coord3DTo1D(x, y, z, CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); } + chunk_index_t calculateIndex(glm::vec3 pos){ + return calculateIndex(static_cast(pos.x), static_cast(pos.y), + static_cast(pos.z)); + } + + chunk_index_t calculateIndex(chunk_intcoord_t i, chunk_intcoord_t j, chunk_intcoord_t k){ + return i | (j << 10) | (k << 20); + } + Chunk::Chunk(glm::vec3 pos) { this->position = pos; this->setState(CHUNK_STATE_EMPTY, true); this->setBlocks(0, CHUNK_MAX_INDEX, Block::AIR); + this->index = calculateIndex(pos); } Chunk ::~Chunk() diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index 917e476..6f0d6d9 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -24,7 +24,7 @@ namespace chunkmanager // Concurrent hash table of chunks ChunkTable chunks; // Chunk indices. Centered at (0,0,0), going in concentric sphere outwards - std::array, chunks_volume> chunks_indices; + std::array, chunks_volume> chunks_indices; /* Multithreading */ std::atomic_bool should_run; @@ -37,47 +37,18 @@ namespace chunkmanager int block_to_place{2}; // Init chunkmanager. Chunk indices and start threads - int chunks_volume_real; void init(){ int index{0}; - int rr{RENDER_DISTANCE * RENDER_DISTANCE}; - int xp{0}, x{0}; - bool b = true; + for(chunk_intcoord_t i = -RENDER_DISTANCE; i < RENDER_DISTANCE; i++) + for(chunk_intcoord_t j = -RENDER_DISTANCE; j < RENDER_DISTANCE; j++) + for(chunk_intcoord_t k = -RENDER_DISTANCE; k < RENDER_DISTANCE; k++){ - // Iterate over all chunks, in concentric spheres starting fron the player and going outwards. Alternate left and right - // Eq. of the sphere (x - a)² + (y - b)² + (z - c)² = r² - while (xp <= RENDER_DISTANCE) - { - // Alternate between left and right - if (b) x = +xp; - else x = -xp; - - // Step 1. At current x, get the corresponding y values (2nd degree equation, up to 2 - // possible results) - int y1 = static_cast(sqrt((rr) - x*x)); - - for (int y = -y1 + 1 ; y <= y1; y++) - { - // Step 2. At both y's, get the corresponding z values - int z1 = static_cast(sqrt( rr - x*x - y*y)); - - for (int z = -z1 + 1; z <= z1; z++){ - chunks_indices[index][0] = x; - chunks_indices[index][1] = y; - chunks_indices[index][2] = z; + chunks_indices[index][0]=i; + chunks_indices[index][1]=j; + chunks_indices[index][2]=k; index++; } - } - - if (!b) - { - xp++; - b = true; - } - else b = false; - } - chunks_volume_real = index; // Also init mesh data queue for(int i = 0; i < 10; i++) @@ -95,8 +66,9 @@ namespace chunkmanager void generate(){ while(should_run){ ChunkPQEntry entry; - while(chunks_to_generate_queue.try_pop(entry)) generateChunk(entry.first); + if(chunks_to_generate_queue.try_pop(entry)) generateChunk(entry.first); } + chunks_to_generate_queue.clear(); } // Method for chunk meshing thread(s) @@ -111,6 +83,7 @@ namespace chunkmanager } } } + chunks_to_mesh_queue.clear(); } oneapi::tbb::concurrent_queue chunks_todelete; @@ -121,24 +94,14 @@ namespace chunkmanager int chunkY=static_cast(theCamera.getAtomicPosY() / CHUNK_SIZE); int chunkZ=static_cast(theCamera.getAtomicPosZ() / CHUNK_SIZE); - debug::window::set_parameter("px", theCamera.getAtomicPosX()); - debug::window::set_parameter("py", theCamera.getAtomicPosY()); - debug::window::set_parameter("pz", theCamera.getAtomicPosZ()); - debug::window::set_parameter("cx", chunkX); - debug::window::set_parameter("cy", chunkY); - debug::window::set_parameter("cz", chunkZ); - debug::window::set_parameter("lx", theCamera.getFront().x); - debug::window::set_parameter("ly", theCamera.getFront().y); - debug::window::set_parameter("lz", theCamera.getFront().z); - // Update other chunks - for(int i = 0; i < chunks_volume_real; i++) { - const uint16_t x = chunks_indices[i][0] + chunkX; - const uint16_t y = chunks_indices[i][1] + chunkY; - const uint16_t z = chunks_indices[i][2] + chunkZ; - const uint32_t index = calculateIndex(x, y, z); + for(int i = 0; i < chunks_volume; i++) { + const chunk_intcoord_t x = chunks_indices[i][0] + chunkX; + const chunk_intcoord_t y = chunks_indices[i][1] + chunkY; + const chunk_intcoord_t z = chunks_indices[i][2] + chunkZ; - if(x > 1023 || y > 1023 || z > 1023) continue; + if(x < 0 || y < 0 || z < 0 || x > 1023 || y > 1023 || z > 1023) continue; + const chunk_index_t index = Chunk::calculateIndex(x, y, z); ChunkTable::accessor a, a1, a2, b1, b2, c1, c2; if(!chunks.find(a, index)) chunks.emplace(a, std::make_pair(index, new Chunk::Chunk(glm::vec3(x,y,z)))); @@ -147,17 +110,17 @@ namespace chunkmanager chunks_to_generate_queue.push(std::make_pair(a->second, GENERATION_PRIORITY_NORMAL)); }else if(! (a->second->getState(Chunk::CHUNK_STATE_MESHED))){ if( - (x + 1 > 1023 || (chunks.find(a1, calculateIndex(x+1, y, z)) && + (x + 1 > 1023 || (chunks.find(a1, Chunk::calculateIndex(x+1, y, z)) && a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) && - (x - 1 < 0|| (chunks.find(a1, calculateIndex(x-1, y, z)) && + (x - 1 < 0|| (chunks.find(a1, Chunk::calculateIndex(x-1, y, z)) && a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) && - (y + 1 > 1023 || (chunks.find(a1, calculateIndex(x, y+1, z)) && + (y + 1 > 1023 || (chunks.find(a1, Chunk::calculateIndex(x, y+1, z)) && a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) && - (y - 1 < 0|| (chunks.find(a1, calculateIndex(x, y-1, z)) && + (y - 1 < 0|| (chunks.find(a1, Chunk::calculateIndex(x, y-1, z)) && a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) && - (z + 1 > 1023 || (chunks.find(a1, calculateIndex(x, y, z+1)) && + (z + 1 > 1023 || (chunks.find(a1, Chunk::calculateIndex(x, y, z+1)) && a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) && - (z - 1 < 0|| (chunks.find(a1, calculateIndex(x, y, z-1)) && + (z - 1 < 0|| (chunks.find(a1, Chunk::calculateIndex(x, y, z-1)) && a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) ) chunks_to_mesh_queue.push(std::make_pair(a->second, MESHING_PRIORITY_NORMAL)); @@ -172,11 +135,11 @@ namespace chunkmanager Chunk::Chunk* n; nUnloaded = 0; while(chunks_todelete.try_pop(n)){ - int x = static_cast(n->getPosition().x); - int y = static_cast(n->getPosition().y); - int z = static_cast(n->getPosition().z); + chunk_intcoord_t x = static_cast(n->getPosition().x); + chunk_intcoord_t y = static_cast(n->getPosition().y); + chunk_intcoord_t z = static_cast(n->getPosition().z); if(x > 1023 || y > 1023 || z > 1023) continue; - const uint32_t index = calculateIndex(x, y, z); + const uint32_t index = Chunk::calculateIndex(x, y, z); chunks.erase(index); //delete n; @@ -185,20 +148,21 @@ namespace chunkmanager } } - // uint32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1023). There's actually two spare bits - uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k){ - return i | (j << 10) | (k << 20); - } - oneapi::tbb::concurrent_queue& getDeleteVector(){ return chunks_todelete; } - std::array, chunks_volume>& getChunksIndices(){ return chunks_indices; } + std::array, chunks_volume>& getChunksIndices(){ return chunks_indices; } void stop() { should_run=false; + + std::cout << "Waiting for secondary threads to shut down" << std::endl; update_thread.join(); + std::cout << "Update thread has terminated" << std::endl; gen_thread.join(); + std::cout << "Generation thread has terminated" << std::endl; mesh_thread.join(); + std::cout << "Meshing thread has terminated" << std::endl; } + void destroy(){ /*for(const auto& n : chunks){ delete n.second; @@ -225,7 +189,7 @@ namespace chunkmanager if(px < 0 || py < 0 || pz < 0 || px >= 1024 || py >= 1024 || pz >= 1024) continue; ChunkTable::accessor a; - if(!chunks.find(a, calculateIndex(px, py, pz))) continue; + if(!chunks.find(a, Chunk::calculateIndex(px, py, pz))) continue; Chunk::Chunk* c = a->second; if(!c->getState(Chunk::CHUNK_STATE_GENERATED) || c->getState(Chunk::CHUNK_STATE_EMPTY)) continue; @@ -254,7 +218,7 @@ namespace chunkmanager // exit early if the position is invalid or the chunk does not exist if(px1 < 0 || py1 < 0 || pz1 < 0 || px1 >= 1024 || py1 >= 1024 || pz1 >= 1024) return; ChunkTable::accessor a1; - if(!chunks.find(a1, calculateIndex(px1, py1, pz1))) return; + if(!chunks.find(a1, Chunk::calculateIndex(px1, py1, pz1))) return; Chunk::Chunk* c1 = a1->second; // place the new block (only stone for now) c1->setBlock((Block)block_to_place, bx1, by1, bz1); @@ -276,17 +240,17 @@ namespace chunkmanager // When necessary, also mesh nearby chunks ChunkTable::accessor a1, a2, b1, b2, c1, c2; - if(bx == 0 && px - 1 >= 0 && chunks.find(a1, calculateIndex(px - 1, py, pz))) + if(bx == 0 && px - 1 >= 0 && chunks.find(a1, Chunk::calculateIndex(px - 1, py, pz))) chunkmesher::mesh(a1->second); - if(by == 0 && py - 1 >= 0 && chunks.find(b1, calculateIndex(px, py - 1, pz))) + if(by == 0 && py - 1 >= 0 && chunks.find(b1, Chunk::calculateIndex(px, py - 1, pz))) chunkmesher::mesh(b1->second); - if(bz == 0 && pz - 1 >= 0 && chunks.find(c1, calculateIndex(px, py, pz - 1))) + if(bz == 0 && pz - 1 >= 0 && chunks.find(c1, Chunk::calculateIndex(px, py, pz - 1))) chunkmesher::mesh(c1->second); - if(bx == CHUNK_SIZE - 1 && px +1 < 1024 && chunks.find(a2, calculateIndex(px +1, py, pz))) + if(bx == CHUNK_SIZE - 1 && px +1 < 1024 && chunks.find(a2, Chunk::calculateIndex(px +1, py, pz))) chunkmesher::mesh(a2->second); - if(by == CHUNK_SIZE - 1 && py +1 < 1024 && chunks.find(b2, calculateIndex(px, py +1, pz))) + if(by == CHUNK_SIZE - 1 && py +1 < 1024 && chunks.find(b2, Chunk::calculateIndex(px, py +1, pz))) chunkmesher::mesh(b2->second); - if(bz == CHUNK_SIZE - 1 && pz +1 < 1024 && chunks.find(c2, calculateIndex(px, py, pz +1))) + if(bz == CHUNK_SIZE - 1 && pz +1 < 1024 && chunks.find(c2, Chunk::calculateIndex(px, py, pz +1))) chunkmesher::mesh(c2->second); debug::window::set_parameter("block_last_action", place); @@ -312,7 +276,7 @@ namespace chunkmanager //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; + if(!chunks.find(a, Chunk::calculateIndex(cx, cy, cz))) return Block::NULLBLK; else { int bx = x % CHUNK_SIZE; int by = y % CHUNK_SIZE; @@ -324,3 +288,4 @@ namespace chunkmanager } } }; + diff --git a/src/controls.cpp b/src/controls.cpp new file mode 100644 index 0000000..235ed96 --- /dev/null +++ b/src/controls.cpp @@ -0,0 +1,39 @@ +#include "controls.hpp" +#include "renderer.hpp" + +namespace controls{ + float lastBlockPick=0.0; + bool blockpick = false; + bool cursor = false; + + void init(){ + } + + void update(GLFWwindow* window){ + float current_time = glfwGetTime(); + + // Reset blockpicking timeout has passed + if(current_time - lastBlockPick > BLOCKPICK_TIMEOUT) blockpick = false; + // Reset blockpicking if both mouse buttons are released + if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_RELEASE && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_RELEASE) blockpick = false; + + if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS && !blockpick){ + //chunkmanager::blockpick(false); + blockpick=true; + lastBlockPick=glfwGetTime(); + } + + if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS && !blockpick){ + //chunkmanager::blockpick(true); + blockpick=true; + lastBlockPick=glfwGetTime(); + } + + if(glfwGetKey(window, GLFW_KEY_F2) == GLFW_PRESS) renderer::saveScreenshot(); + if(glfwGetKey(window, GLFW_KEY_F3) == GLFW_PRESS) renderer::saveScreenshot(true); + if(glfwGetKey(window, GLFW_KEY_M) == GLFW_PRESS) { + cursor = !cursor; + glfwSetInputMode(window, GLFW_CURSOR, cursor ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED); + } + } +}; diff --git a/src/main.cpp b/src/main.cpp index 1f185f4..6aafb51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,26 +4,23 @@ #include #include +#include "main.hpp" + #define GLOBALS_DEFINER #include "globals.hpp" #undef GLOBALS_DEFINER - #include "chunkmanager.hpp" -#include "main.hpp" +#include "controls.hpp" #include "debugwindow.hpp" #include "renderer.hpp" -#include "spacefilling.hpp" #include "shader.hpp" +#include "spacefilling.hpp" float deltaTime = 0.0f; // Time between current frame and last frame float lastFrame = 0.0f; // Time of last frame float lastFPSFrame = 0.0f; int frames = 0; -float lastBlockPick=0.0; -bool blockpick = false; -bool cursor = false; - int main() { @@ -70,6 +67,7 @@ int main() } SpaceFilling::initLUT(); + controls::init(); chunkmanager::init(); debug::window::init(window); renderer::init(window); @@ -94,14 +92,24 @@ int main() glClearColor(0.431f, 0.694f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Input processing - processInput(window); + // Input handling + // Only close event is handles by main + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + // the rest of input processing is handled by controls.cpp + controls::update(window); // Camera theCamera.update(window, deltaTime); - - // Reset blockping timeout if 200ms have passed - if(glfwGetTime() - lastBlockPick > 0.1) blockpick = false; + debug::window::set_parameter("px", theCamera.getPos().x); + debug::window::set_parameter("py", theCamera.getPos().y); + debug::window::set_parameter("pz", theCamera.getPos().z); + debug::window::set_parameter("cx", (int)(theCamera.getPos().x / CHUNK_SIZE)); + debug::window::set_parameter("cy", (int)(theCamera.getPos().y / CHUNK_SIZE)); + debug::window::set_parameter("cz", (int)(theCamera.getPos().z / CHUNK_SIZE)); + debug::window::set_parameter("lx", theCamera.getFront().x); + debug::window::set_parameter("ly", theCamera.getFront().y); + debug::window::set_parameter("lz", theCamera.getFront().z); // Render pass renderer::render(); @@ -134,33 +142,3 @@ void mouse_callback(GLFWwindow *window, double xpos, double ypos) { theCamera.mouseCallback(window, xpos, ypos); } - -void processInput(GLFWwindow *window) -{ - if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) - glfwSetWindowShouldClose(window, true); - - if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS && !blockpick){ - chunkmanager::blockpick(false); - blockpick=true; - lastBlockPick=glfwGetTime(); - } - - if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS && !blockpick){ - chunkmanager::blockpick(true); - blockpick=true; - lastBlockPick=glfwGetTime(); - } - - // Reset blockpicking if enough time has passed - if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_RELEASE && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_RELEASE) blockpick = false; - - if(glfwGetKey(window, GLFW_KEY_F2) == GLFW_PRESS) renderer::saveScreenshot(); - if(glfwGetKey(window, GLFW_KEY_F3) == GLFW_PRESS) renderer::saveScreenshot(true); - if(glfwGetKey(window, GLFW_KEY_M) == GLFW_PRESS) { - cursor = !cursor; - glfwSetInputMode(window, GLFW_CURSOR, cursor ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED); - } - - -} diff --git a/src/renderer.cpp b/src/renderer.cpp index 8f1ae97..ab8cd16 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -149,37 +149,36 @@ namespace renderer{ if(dist <= static_cast(RENDER_DISTANCE)){ if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue; - // Increase total vertex count - vertices += c->numVertices; + if(c->numVertices > 0){ + // Increase total vertex count + vertices += c->numVertices; - // reset out-of-vision and unload flags - c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false); - c->setState(Chunk::CHUNK_STATE_UNLOADED, false); + // reset out-of-vision and unload flags + c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false); + c->setState(Chunk::CHUNK_STATE_UNLOADED, false); - // Perform frustum culling and eventually render - glm::vec3 chunk = c->getPosition(); - glm::vec4 chunkW = glm::vec4(chunk.x*static_cast(CHUNK_SIZE), chunk.y*static_cast(CHUNK_SIZE), chunk.z*static_cast(CHUNK_SIZE),1.0); - glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk); + // Perform frustum culling and eventually render + glm::vec3 chunk = c->getPosition(); + glm::vec4 chunkW = glm::vec4(chunk.x*static_cast(CHUNK_SIZE), chunk.y*static_cast(CHUNK_SIZE), chunk.z*static_cast(CHUNK_SIZE),1.0); + glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk); - // Check if all the corners of the chunk are outside any of the planes - // TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each - // plane against each corner of the chunk - bool out=false; - int a{0}; - for(int p = 0; p < 6; p++){ - a = 0; - for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y - + ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0; + // Check if all the corners of the chunk are outside any of the planes + // TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each + // plane against each corner of the chunk + bool out=false; + int a{0}; + for(int p = 0; p < 6; p++){ + a = 0; + for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y + + ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0; - if(a==8){ - out=true; - break; + if(a==8){ + out=true; + break; + } } - } - if (!out) - { - if(c->numVertices > 0) + if (!out) { theShader->setMat4("model", model); theShader->setMat4("view", theCamera.getView());