From 880c634be0e2a0ca944d3b8e079509e2141d94cb Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Thu, 21 Sep 2023 15:43:51 +0200 Subject: [PATCH 1/9] camera: set atomic position at startup this avoids the first few chunk update loops recognizing the camera as being positioned at (0,0,0), which in turns avoids wastefully generating chunks out of view at startup --- include/camera.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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); From 353ef37186871ce3d8e0fabe532f7da2d6a49224 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 21:35:50 +0200 Subject: [PATCH 2/9] renderer: perform frustum culling only if chunk has vertices --- src/renderer.cpp | 49 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 25 deletions(-) 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()); From f6f40571094abf75e71827a13364e9361c51dffd Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 21:57:09 +0200 Subject: [PATCH 3/9] update player debug variables in main instead of chunkmgr --- src/chunkmanager.cpp | 10 ---------- src/main.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index 917e476..97b0adf 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -121,16 +121,6 @@ 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; diff --git a/src/main.cpp b/src/main.cpp index 1f185f4..70d0a44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -99,6 +99,15 @@ int main() // Camera theCamera.update(window, deltaTime); + 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); // Reset blockping timeout if 200ms have passed if(glfwGetTime() - lastBlockPick > 0.1) blockpick = false; From ca043bac68f6fa4bf797108ff970e191d4a7ea2a Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 22:01:32 +0200 Subject: [PATCH 4/9] threads: allow for proper shutdown using `if` instead of `while` avoids the need to wait for the queue to empty to shutdown the thread --- src/chunkmanager.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index 97b0adf..1d5758b 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -95,8 +95,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 +112,7 @@ namespace chunkmanager } } } + chunks_to_mesh_queue.clear(); } oneapi::tbb::concurrent_queue chunks_todelete; @@ -185,10 +187,16 @@ namespace chunkmanager 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; @@ -314,3 +322,4 @@ namespace chunkmanager } } }; + From 2a57796ed2ef6dff8b0d914fb56b4f0f942f57c8 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 18:16:45 +0200 Subject: [PATCH 5/9] move input handling from main into dedicated file --- include/controls.hpp | 14 ++++++++++++ include/main.hpp | 1 - src/CMakeLists.txt | 2 +- src/controls.cpp | 39 ++++++++++++++++++++++++++++++++ src/main.cpp | 53 +++++++++----------------------------------- 5 files changed, 65 insertions(+), 44 deletions(-) create mode 100644 include/controls.hpp create mode 100644 src/controls.cpp 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/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/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 70d0a44..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,8 +92,12 @@ 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); @@ -108,9 +110,6 @@ int main() debug::window::set_parameter("lx", theCamera.getFront().x); debug::window::set_parameter("ly", theCamera.getFront().y); debug::window::set_parameter("lz", theCamera.getFront().z); - - // Reset blockping timeout if 200ms have passed - if(glfwGetTime() - lastBlockPick > 0.1) blockpick = false; // Render pass renderer::render(); @@ -143,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); - } - - -} From c6d00c4200e8e63d784ee1dd34ac2759ce4e6d3b Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 22:25:46 +0200 Subject: [PATCH 6/9] fix type mismatch in chunk index/coordinates typedef an appropriate chunk_index_t and chunk_intcoord_t --- include/chunkmanager.hpp | 9 ++++++--- src/chunkmanager.cpp | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/include/chunkmanager.hpp b/include/chunkmanager.hpp index b32a9af..a185381 100644 --- a/include/chunkmanager.hpp +++ b/include/chunkmanager.hpp @@ -17,9 +17,12 @@ #define MESHING_PRIORITY_PLAYER_EDIT 10 #define GENERATION_PRIORITY_NORMAL 0 +typedef int16_t chunk_intcoord_t; +typedef int32_t chunk_index_t; + 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 +34,12 @@ namespace chunkmanager void init(); void blockpick(bool place); - uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k); + chunk_index_t calculateIndex(chunk_intcoord_t i, chunk_intcoord_t j, chunk_intcoord_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/src/chunkmanager.cpp b/src/chunkmanager.cpp index 1d5758b..54cf67a 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; @@ -42,7 +42,7 @@ namespace chunkmanager int index{0}; int rr{RENDER_DISTANCE * RENDER_DISTANCE}; - int xp{0}, x{0}; + chunk_intcoord_t xp{0}, x{0}; bool b = true; // Iterate over all chunks, in concentric spheres starting fron the player and going outwards. Alternate left and right @@ -55,14 +55,14 @@ namespace chunkmanager // 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)); + chunk_intcoord_t y1 = static_cast(sqrt((rr) - x*x)); - for (int y = -y1 + 1 ; y <= y1; y++) + for (chunk_intcoord_t 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)); + chunk_intcoord_t z1 = static_cast(sqrt( rr - x*x - y*y)); - for (int z = -z1 + 1; z <= z1; z++){ + for (chunk_intcoord_t z = -z1 + 1; z <= z1; z++){ chunks_indices[index][0] = x; chunks_indices[index][1] = y; chunks_indices[index][2] = z; @@ -125,12 +125,12 @@ namespace chunkmanager // 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); + 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 = 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)))); @@ -164,9 +164,9 @@ 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); @@ -178,12 +178,12 @@ 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){ + chunk_index_t calculateIndex(chunk_intcoord_t i, chunk_intcoord_t j, chunk_intcoord_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; From 490f207e3937ec6abca846c2d5484f97038794c4 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 22:30:42 +0200 Subject: [PATCH 7/9] chunk/mgr: calculate index belongs to chunk namespace --- include/chunk.hpp | 7 +++++++ include/chunkmanager.hpp | 4 ---- src/chunk.cpp | 9 +++++++++ src/chunkmanager.cpp | 39 +++++++++++++++++---------------------- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/include/chunk.hpp b/include/chunk.hpp index 17f29fb..5ecafe4 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; diff --git a/include/chunkmanager.hpp b/include/chunkmanager.hpp index a185381..b393760 100644 --- a/include/chunkmanager.hpp +++ b/include/chunkmanager.hpp @@ -17,9 +17,6 @@ #define MESHING_PRIORITY_PLAYER_EDIT 10 #define GENERATION_PRIORITY_NORMAL 0 -typedef int16_t chunk_intcoord_t; -typedef int32_t chunk_index_t; - namespace chunkmanager { typedef oneapi::tbb::concurrent_hash_map ChunkTable; @@ -34,7 +31,6 @@ namespace chunkmanager void init(); void blockpick(bool place); - chunk_index_t calculateIndex(chunk_intcoord_t i, chunk_intcoord_t j, chunk_intcoord_t k); void stop(); void destroy(); diff --git a/src/chunk.cpp b/src/chunk.cpp index b14fffc..f7822e0 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -15,6 +15,15 @@ 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; diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index 54cf67a..8a413de 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -130,7 +130,7 @@ namespace chunkmanager const chunk_intcoord_t z = chunks_indices[i][2] + chunkZ; if(x < 0 || y < 0 || z < 0 || x > 1023 || y > 1023 || z > 1023) continue; - const chunk_index_t index = calculateIndex(x, y, z); + 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)))); @@ -139,17 +139,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)); @@ -168,7 +168,7 @@ namespace chunkmanager 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; @@ -177,11 +177,6 @@ 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 - chunk_index_t calculateIndex(chunk_intcoord_t i, chunk_intcoord_t j, chunk_intcoord_t k){ - return i | (j << 10) | (k << 20); - } - oneapi::tbb::concurrent_queue& getDeleteVector(){ return chunks_todelete; } std::array, chunks_volume>& getChunksIndices(){ return chunks_indices; } @@ -223,7 +218,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; @@ -252,7 +247,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); @@ -274,17 +269,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); @@ -310,7 +305,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; From 60bbc8568246b601094bcc7fc48b30747ef8acdf Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 22:32:16 +0200 Subject: [PATCH 8/9] chunk: store index in chunk itself --- include/chunk.hpp | 3 +++ src/chunk.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/include/chunk.hpp b/include/chunk.hpp index 5ecafe4..26a7f86 100644 --- a/include/chunk.hpp +++ b/include/chunk.hpp @@ -65,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/src/chunk.cpp b/src/chunk.cpp index f7822e0..982edf8 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -29,6 +29,7 @@ namespace Chunk this->position = pos; this->setState(CHUNK_STATE_EMPTY, true); this->setBlocks(0, CHUNK_MAX_INDEX, Block::AIR); + this->index = calculateIndex(pos); } Chunk ::~Chunk() From 1a50d1fb8444865e537146840960e80f922951b4 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Tue, 3 Oct 2023 22:41:06 +0200 Subject: [PATCH 9/9] chunkmgr: span chunk indices in a cube around the player, not a sphere --- include/globals.hpp | 3 ++- src/chunkmanager.cpp | 43 +++++++------------------------------------ 2 files changed, 9 insertions(+), 37 deletions(-) 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/src/chunkmanager.cpp b/src/chunkmanager.cpp index 8a413de..6f0d6d9 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -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}; - chunk_intcoord_t 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) - chunk_intcoord_t y1 = static_cast(sqrt((rr) - x*x)); - - for (chunk_intcoord_t y = -y1 + 1 ; y <= y1; y++) - { - // Step 2. At both y's, get the corresponding z values - chunk_intcoord_t z1 = static_cast(sqrt( rr - x*x - y*y)); - - for (chunk_intcoord_t 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++) @@ -124,7 +95,7 @@ namespace chunkmanager int chunkZ=static_cast(theCamera.getAtomicPosZ() / CHUNK_SIZE); // Update other chunks - for(int i = 0; i < chunks_volume_real; i++) { + 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;