diff --git a/include/chunkmanager.hpp b/include/chunkmanager.hpp index dca0aaa..ed575ce 100644 --- a/include/chunkmanager.hpp +++ b/include/chunkmanager.hpp @@ -18,6 +18,9 @@ namespace chunkmanager void updateChunk(uint32_t, uint16_t, uint16_t, uint16_t); void destroy(); + void blockpick(bool place); + uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k); + void mesh(); void generate(); diff --git a/src/chunk.cpp b/src/chunk.cpp index 7a08044..5a35682 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -6,6 +6,7 @@ #include "intervalmap.hpp" #include "globals.hpp" +#include namespace Chunk { @@ -17,13 +18,12 @@ namespace Chunk Chunk::Chunk(glm::vec3 pos) { this->position = pos; - this->blocks.insert(0, CHUNK_VOLUME, Block::AIR); this->setState(CHUNK_STATE_EMPTY, true); // std::cout << "CHUNK" << std::endl; - glGenVertexArrays(1, &(this->VAO)); - glGenBuffers(1, &(this->colorBuffer)); - glGenBuffers(1, &(this->VBO)); - glGenBuffers(1, &(this->EBO)); + glGenVertexArrays(1, &(this->VAO)); + glGenBuffers(1, &(this->colorBuffer)); + glGenBuffers(1, &(this->VBO)); + glGenBuffers(1, &(this->EBO)); } @@ -49,7 +49,7 @@ namespace Chunk void Chunk::setBlock(Block b, int x, int y, int z) { int coord = HILBERT_XYZ_ENCODE[x][y][z]; - blocks.insert(coord <= 0 ? 0 : coord, coord+1 >= CHUNK_VOLUME ? CHUNK_VOLUME : coord+1, b); + this->setBlocks(coord, coord+1, b); } void Chunk::setBlocks(int start, int end, Block b){ diff --git a/src/chunkgenerator.cpp b/src/chunkgenerator.cpp index e114354..120076e 100644 --- a/src/chunkgenerator.cpp +++ b/src/chunkgenerator.cpp @@ -90,4 +90,4 @@ void generatePyramid(Chunk::Chunk *chunk) for (int k = 0; k < CHUNK_SIZE; k++) // blocks[utils::coord3DTo1D(i, j, k, CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE)] = j == 0 ? Block::STONE : Block::AIR; chunk->setBlock(i >= j && i < CHUNK_SIZE - j && k >= j && k < CHUNK_SIZE - j ? (j & 1) == 0 ? Block::GRASS : Block::STONE : Block::AIR, i, j, k); -} \ No newline at end of file +} diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index d1b37dc..30bf61f 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -97,6 +97,8 @@ namespace chunkmanager std::unordered_map to_delete; std::set to_delete_delete; + glm::vec3 cameraPos = theCamera.getPos(); + int chunkX, chunkY, chunkZ; void update(float deltaTime) { int nUnloaded{0}; @@ -107,9 +109,9 @@ namespace chunkmanager // Iterate over all chunks, in concentric spheres starting fron the player and going outwards // Eq. of the sphere (x - a)² + (y - b)² + (z - c)² = r² - glm::vec3 cameraPos = theCamera.getPos(); + cameraPos = theCamera.getPos(); theCamera.getFrustumPlanes(frustumPlanes, true); - int chunkX{(static_cast(cameraPos.x)) / CHUNK_SIZE}, chunkY{(static_cast(cameraPos.y)) / CHUNK_SIZE}, chunkZ{(static_cast(cameraPos.z)) / CHUNK_SIZE}; + chunkX=(static_cast(cameraPos.x)) / CHUNK_SIZE; chunkY=(static_cast(cameraPos.y)) / CHUNK_SIZE; chunkZ=(static_cast(cameraPos.z)) / CHUNK_SIZE; std::time_t currentTime = std::time(nullptr); // Check for far chunks that need to be cleaned up from memory @@ -190,7 +192,8 @@ namespace chunkmanager else k = z; - uint32_t in = i | (j << 10) | (k << 20); // uint32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1024). There's actually two spare bits + // uint32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1024). There's actually two spare bits + uint32_t in = calculateIndex(i, j, k); chunkmanager::updateChunk(in, i, j, k); } } @@ -321,6 +324,77 @@ namespace chunkmanager } } + void blockpick(bool place){ + // cast a ray from the camera in the direction pointed by the camera itself + glm::vec3 pos = cameraPos; + for(float t = 0.0; t <= 25.0; t += 0.5){ + // traverse the ray a block at the time + pos = theCamera.getPos() + t * theCamera.getFront(); + + // get which chunk and block the ray is at + int px = ((int)(pos.x))/CHUNK_SIZE; + int py = ((int)(pos.y))/CHUNK_SIZE; + int pz = ((int)(pos.z))/CHUNK_SIZE; + int bx = pos.x - px*CHUNK_SIZE; + int by = pos.y - py*CHUNK_SIZE; + int bz = pos.z - pz*CHUNK_SIZE; + + // exit early if the position is invalid or the chunk does not exist + if(px < 0 || py < 0 || pz < 0) return; + if(chunks.find(calculateIndex(px, py, pz)) == chunks.end()) return; + + Chunk::Chunk* c = chunks.at(calculateIndex(px, py, pz)); + Block b = c->getBlock(bx, by, bz); + + // if the block is non empty + if(b != Block::AIR){ + + // if placing a new block + if(place){ + // Go half a block backwards on the ray, to check the block where the ray was + // coming from + // Doing this and not using normal adds the unexpected (and unwanted) ability to + // place blocks diagonally, without faces colliding with the block that has + // been clicked + pos -= theCamera.getFront()*0.5f; + + int px1 = ((int)(pos.x))/CHUNK_SIZE; + int py1 = ((int)(pos.y))/CHUNK_SIZE; + int pz1 = ((int)(pos.z))/CHUNK_SIZE; + int bx1 = pos.x - px1*CHUNK_SIZE; + int by1 = pos.y - py1*CHUNK_SIZE; + int bz1 = pos.z - pz1*CHUNK_SIZE; + + // exit early if the position is invalid or the chunk does not exist + if(px1 < 0 || py1 < 0 || pz1 < 0) return; + if(chunks.find(calculateIndex(px1, py1, pz1)) == chunks.end()) return; + + Chunk::Chunk* c1 = chunks.at(calculateIndex(px1, py1, pz1)); + // place the new block (only stone for now) + c1->setBlock( Block::STONE, bx1, by1, bz1); + + // update the mesh of the chunk + chunkmesher::mesh(c1); + // mark the mesh of the chunk the be updated on the gpu + c1->setState(Chunk::CHUNK_STATE_MESH_LOADED, false); + }else{ + // replace the current block with air to remove it + c->setBlock( Block::AIR, bx, by, bz); + + // update the mesh of the chunk + chunkmesher::mesh(c); + // mark the mesh of the chunk the be updated on the gpu + c->setState(Chunk::CHUNK_STATE_MESH_LOADED, false); + } + break; + } + } + } + + uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k){ + return i | (j << 10) | (k << 20); + } + void destroy() { for (auto &n : chunks) diff --git a/src/main.cpp b/src/main.cpp index 1b9e42e..f707be1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,9 @@ float lastFrame = 0.0f; // Time of last frame float lastFPSFrame = 0.0f; int frames = 0; +float lastBlockPick=0.0; +bool blockpick = false; + int main() { @@ -76,6 +79,8 @@ int main() lastFPSFrame = currentFrame; } + if(glfwGetTime() - lastBlockPick > 0.2) blockpick = false; + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -123,4 +128,16 @@ 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(); + } + if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_RELEASE && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_RELEASE) blockpick = false; + }