diff --git a/blockpick_aw b/blockpick_aw new file mode 100644 index 0000000..ef00baa --- /dev/null +++ b/blockpick_aw @@ -0,0 +1,153 @@ + + // Traverse voxel using Amanatides&Woo traversal algorithm + // http://www.cse.yorku.ca/~amana/research/grid.pdf + + glm::vec3 pos = msg.cameraPos; + glm::vec3 front = msg.cameraFront; + + int chunkX, chunkY, chunkZ, blockX, blockY, blockZ, old_blockX, old_blockY, old_blockZ; + Chunk::Chunk* old_chunk = nullptr; + + // The ray has equation pos + t*front + + // Initialize phase + // Origin integer voxel coordinates + // Avoid floating point accuracy errors: work as close to 0 as possible, translate + // everything later + int basex = std::floor(pos.x); + int basey = std::floor(pos.y); + int basez = std::floor(pos.z); + double x = pos.x - basex; + double y = pos.y - basey; + double z = pos.z - basez; + /*double x = std::floor(pos.x + 0.5d); + double y = std::floor(pos.y + 0.5d); + double z = std::floor(pos.z + 0.5d); + */ + + auto sign = [=](double f){ return f > 0 ? 1 : f < 0 ? -1 : 0; }; + auto tmax = [=](double p, double dir){ + int s = sign(dir); + + double b = std::floor(p + 0.5d); + if(s > 0) + return (b + 1 - p) / dir; + else if(s < 0) + return (p - b) / dir; + return 0.0; + }; + + + // Step + int stepX = sign(front.x); + int stepY = sign(front.y); + int stepZ = sign(front.z); + + // tMax: the value of t at which the ray crosses the first voxel boundary + double tMaxX = tmax(x, front.x); + double tMaxY = tmax(y, front.y); + double tMaxZ = tmax(z, front.z); + + // tDelta: how far along the ray along they ray (in units of t) for the _ component of such + // a movement to equal the width of a voxel + double tDeltaX = stepX / front.x; + double tDeltaY = stepY / front.y; + double tDeltaZ = stepZ / front.z; + + std::cout << "starting blockpick at " << x << "," << y << "," << z << "+(" << basex << "," << + basey << "," << basez << ") with tMax " << tMaxX + << "," << tMaxY << "," << tMaxZ << " and delta " << tDeltaX << "," << tDeltaY << "," << + tDeltaZ << std::endl; + + while(utils::withinDistance(x,y,z,0,0,0,6)){ + if(tMaxX < tMaxY){ + if(tMaxX < tMaxZ) { + x += stepX; + tMaxX += tDeltaX; + }else{ + z += stepZ; + tMaxZ += tDeltaZ; + } + }else{ + if(tMaxY < tMaxZ){ + y += stepY; + tMaxY += tDeltaY; + }else{ + z += stepZ; + tMaxZ += tDeltaZ; + } + } + + + int realx = basex + x; + int realy = basey + y; + int realz = basez + z; + + chunkX = realx / CHUNK_SIZE; + chunkY = realy / CHUNK_SIZE; + chunkZ = realz / CHUNK_SIZE; + + if(chunkX < 0 || chunkY < 0 || chunkZ < 0 || chunkX > 1023 || chunkY > 1023 || chunkZ > + 1023) break; + + blockX = realx - chunkX*CHUNK_SIZE; + blockY = realy - chunkY*CHUNK_SIZE; + blockZ = realz - chunkZ*CHUNK_SIZE; + + std::cout << blockX << "," << blockY << "," << blockZ << std::endl; + + ChunkTable::accessor a; + if(!chunks.find(a, Chunk::calculateIndex(chunkX, chunkY, chunkZ))) break; + Chunk::Chunk* chunk = a->second; + if(!(chunk->isFree() || chunk->getState(Chunk::CHUNK_STATE_GENERATED))) break; + Block block = chunk->getBlock(blockX, blockY, blockZ); + + //chunk->setBlock(msg.block, blockX, blockY, blockZ); + //send_chunk_to_meshing_thread(chunk, MESHING_PRIORITY_PLAYER_EDIT); + if(block != Block::AIR){ + if(msg.msg_type == WorldUpdateMsgType::BLOCKPICK_PLACE){ + if(old_chunk){ + old_chunk->setBlock(msg.block, old_blockX, old_blockY, old_blockZ); + send_chunk_to_meshing_thread(old_chunk, MESHING_PRIORITY_PLAYER_EDIT); + if(chunk != old_chunk) send_chunk_to_meshing_thread(chunk, MESHING_PRIORITY_PLAYER_EDIT); + + debug::window::set_parameter("block_last_action", false); + debug::window::set_parameter("block_last_action_block_type", + (int)(msg.block)); + debug::window::set_parameter("block_last_action_x", (int)x); + debug::window::set_parameter("block_last_action_y", (int)y); + debug::window::set_parameter("block_last_action_z", (int)z); + } + }else{ + chunk->setBlock(Block::AIR, blockX, blockY, blockZ); + send_chunk_to_meshing_thread(chunk, MESHING_PRIORITY_PLAYER_EDIT); + + // When necessary, also mesh nearby chunks + ChunkTable::accessor a1, a2, b1, b2, c1, c2; + if(blockX == 0 && chunkX - 1 >= 0 && chunks.find(a1, Chunk::calculateIndex(chunkX - 1, chunkY, chunkZ))) + send_chunk_to_meshing_thread(a1->second, MESHING_PRIORITY_PLAYER_EDIT); + if(blockY == 0 && chunkY - 1 >= 0 && chunks.find(b1, Chunk::calculateIndex(chunkX, chunkY - 1, chunkZ))) + send_chunk_to_meshing_thread(b1->second, MESHING_PRIORITY_PLAYER_EDIT); + if(blockZ == 0 && chunkZ - 1 >= 0 && chunks.find(c1, Chunk::calculateIndex(chunkX, chunkY, chunkZ - 1))) + send_chunk_to_meshing_thread(c1->second, MESHING_PRIORITY_PLAYER_EDIT); + if(blockX == CHUNK_SIZE - 1 && chunkX +1 < 1024 && chunks.find(a2, Chunk::calculateIndex(chunkX +1, chunkY, chunkZ))) + send_chunk_to_meshing_thread(a2->second, MESHING_PRIORITY_PLAYER_EDIT); + if(blockY == CHUNK_SIZE - 1 && chunkY +1 < 1024 && chunks.find(b2, Chunk::calculateIndex(chunkX, chunkY +1, chunkZ))) + send_chunk_to_meshing_thread(b2->second, MESHING_PRIORITY_PLAYER_EDIT); + if(blockZ == CHUNK_SIZE - 1 && chunkZ +1 < 1024 && chunks.find(c2, Chunk::calculateIndex(chunkX, chunkY, chunkZ +1))) + send_chunk_to_meshing_thread(c2->second, MESHING_PRIORITY_PLAYER_EDIT); + + debug::window::set_parameter("block_last_action", false); + debug::window::set_parameter("block_last_action_block_type", (int) (Block::AIR)); + debug::window::set_parameter("block_last_action_x", (int)x); + debug::window::set_parameter("block_last_action_y", (int)y); + debug::window::set_parameter("block_last_action_z", (int)z); + } + break; + } + + old_chunk = chunk; + old_blockX = blockX; + old_blockY = blockY; + old_blockZ = blockZ; + } diff --git a/blockpick_old b/blockpick_old new file mode 100644 index 0000000..139597f --- /dev/null +++ b/blockpick_old @@ -0,0 +1,2 @@ + + diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index 7fda085..638f7cf 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -277,9 +277,12 @@ namespace chunkmanager } void blockpick(WorldUpdateMsg& msg){ + int old_bx{0}, old_by{0}, old_bz{0}; + Chunk::Chunk* old_chunk; + // cast a ray from the camera in the direction pointed by the camera itself glm::vec3 pos = msg.cameraPos; - for(float t = 0.0; t <= 10.0; t += 0.5){ + for(float t = 0.0; t <= 10.0; t += 0.1){ // traverse the ray a block at the time pos = msg.cameraPos + t*msg.cameraFront; @@ -291,6 +294,8 @@ namespace chunkmanager int by = pos.y - py*CHUNK_SIZE; int bz = pos.z - pz*CHUNK_SIZE; + if(bx == old_bx && by == old_by && bz == old_bz) continue; + // exit early if the position is invalid or the chunk does not exist if(px < 0 || py < 0 || pz < 0 || px >= 1024 || py >= 1024 || pz >= 1024) continue; @@ -307,31 +312,14 @@ namespace chunkmanager // if placing a new block if(msg.msg_type == WorldUpdateMsgType::BLOCKPICK_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 || px1 >= 1024 || py1 >= 1024 || pz1 >= 1024) return; - ChunkTable::accessor a1; - 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(msg.block, bx1, by1, bz1); + if(!old_chunk) break; + + old_chunk->setBlock(msg.block, old_bx, old_by, old_bz); // mark the mesh of the chunk the be updated - chunks_to_mesh_queue.push(std::make_pair(c1, MESHING_PRIORITY_PLAYER_EDIT)); - chunks_to_mesh_queue.push(std::make_pair(c, MESHING_PRIORITY_PLAYER_EDIT)); + chunks_to_mesh_queue.push(std::make_pair(old_chunk, MESHING_PRIORITY_PLAYER_EDIT)); + if(c != old_chunk) chunks_to_mesh_queue.push(std::make_pair(c, MESHING_PRIORITY_PLAYER_EDIT)); debug::window::set_parameter("block_last_action", true); debug::window::set_parameter("block_last_action_block_type", (int)(msg.block)); @@ -368,6 +356,11 @@ namespace chunkmanager } break; } + + old_chunk = c; + old_bx = bx; + old_by = by; + old_bz = bz; } }