blockpick: skip iteration if block has not changed
parent
0560fd43c6
commit
f3d8ffed54
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue