// 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; }