Renderer/src/main/java/electrosphere/client/block/solver/RoomSolver.java
austin 5def6da2de
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
break out room solver
2025-05-16 17:05:13 -04:00

101 lines
3.9 KiB
Java

package electrosphere.client.block.solver;
import java.util.LinkedList;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData;
import electrosphere.client.block.ClientBlockSelection;
import electrosphere.client.interact.select.AreaSelection;
import electrosphere.client.interact.select.AreaSelection.AreaSelectionType;
import electrosphere.client.scene.ClientWorldData;
import electrosphere.data.block.fab.RoomMetadata;
import electrosphere.data.block.fab.StructureMetadata;
/**
* Solves for the rooms in a structure
*/
public class RoomSolver {
/**
* Maximum radius of room in blocks
*/
public static final int MAX_ROOM_SIZE = 20;
/**
* 6-connected neighbors (orthogonal)
*/
static final int[][] NEIGHBORS = {
{ 1, 0, 0}, {-1, 0, 0},
{ 0, 1, 0}, { 0,-1, 0},
{ 0, 0, 1}, { 0, 0,-1}
};
/**
* Computes rooms from the currently selected voxels
*/
public static void computeRoomsFromSelection(AreaSelection boundingArea, StructureMetadata structureMetadata){
if(boundingArea.getType() != AreaSelectionType.RECTANGULAR){
throw new Error("Unsupported type! " + boundingArea.getType());
}
int dimX = (int)Math.ceil((boundingArea.getRectEnd().x - boundingArea.getRectStart().x) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE);
int dimY = (int)Math.ceil((boundingArea.getRectEnd().y - boundingArea.getRectStart().y) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE);
int dimZ = (int)Math.ceil((boundingArea.getRectEnd().z - boundingArea.getRectStart().z) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE);
int[][][] distField = ClientBlockSelection.computeCavitySDF(boundingArea);
LinkedList<Vector3i> localMaximums = new LinkedList<Vector3i>();
for(int x = 0; x < dimX; x++){
for(int y = 0; y < dimY; y++){
for(int z = 0; z < dimZ; z++){
//don't consider edges of SDF
if(x == 0 || y == 0 || z == 0 || x == dimX - 1 || y == dimY - 1 || z == dimZ - 1){
continue;
}
if(
distField[x][y][z] >= distField[x-1][y][z] &&
distField[x][y][z] >= distField[x+1][y][z] &&
distField[x][y][z] >= distField[x][y-1][z] &&
distField[x][y][z] >= distField[x][y+1][z] &&
distField[x][y][z] >= distField[x][y][z-1] &&
distField[x][y][z] >= distField[x][y][z+1]
){
localMaximums.add(new Vector3i(x,y,z));
}
}
}
}
while(localMaximums.size() > 0){
Vector3i toConsider = localMaximums.poll();
Vector3d selectionStart = new Vector3d(boundingArea.getRectStart()).add(
toConsider.x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
toConsider.y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
toConsider.z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
//make sure it's not already interecting any solved rooms
boolean contained = false;
for(RoomMetadata room : structureMetadata.getRooms()){
if(room.getArea().containsPoint(selectionStart)){
contained = true;
break;
}
}
if(contained){
continue;
}
//create the new room
Vector3i roomCenterChunkPos = ClientWorldData.convertRealToChunkSpace(selectionStart);
Vector3i roomCenterBlockPos = ClientWorldData.convertRealToLocalBlockSpace(selectionStart);
AreaSelection roomArea = AreaSelection.selectRectangularBlockCavity(roomCenterChunkPos, roomCenterBlockPos, MAX_ROOM_SIZE);
structureMetadata.getRooms().add(new RoomMetadata(roomArea));
}
}
}