diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 14ebb9a3..80b48806 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1851,6 +1851,7 @@ Script engine direct access to joml vectors Script engine passing objects back into methods successfully Room detection within structures Structure metadata organization +Break out room solver diff --git a/src/main/java/electrosphere/client/block/solver/RoomSolver.java b/src/main/java/electrosphere/client/block/solver/RoomSolver.java new file mode 100644 index 00000000..d284ac57 --- /dev/null +++ b/src/main/java/electrosphere/client/block/solver/RoomSolver.java @@ -0,0 +1,100 @@ +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 localMaximums = new LinkedList(); + 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)); + } + + } + +} diff --git a/src/main/java/electrosphere/client/ui/menu/editor/ImGuiStructureTab.java b/src/main/java/electrosphere/client/ui/menu/editor/ImGuiStructureTab.java index 11fd2165..2d87787a 100644 --- a/src/main/java/electrosphere/client/ui/menu/editor/ImGuiStructureTab.java +++ b/src/main/java/electrosphere/client/ui/menu/editor/ImGuiStructureTab.java @@ -5,6 +5,7 @@ import java.io.File; import org.joml.Vector3d; import electrosphere.client.block.ClientBlockSelection; +import electrosphere.client.block.solver.RoomSolver; import electrosphere.client.interact.select.AreaSelection; import electrosphere.data.block.fab.BlockFab; import electrosphere.data.block.fab.BlockFabMetadata; @@ -40,7 +41,7 @@ public class ImGuiStructureTab { } } if(Globals.clientState.currentStructureData != null && ImGui.button("Calculate Rooms")){ - Globals.clientState.currentStructureData.computeRoomsFromSelection(); + RoomSolver.computeRoomsFromSelection(Globals.cursorState.getAreaSelection(),Globals.clientState.currentStructureData); } if(ImGui.button("Convert current selection to room")){ AreaSelection currentSelection = Globals.cursorState.getAreaSelection(); diff --git a/src/main/java/electrosphere/data/block/fab/StructureMetadata.java b/src/main/java/electrosphere/data/block/fab/StructureMetadata.java index 04ffcfc1..2c544483 100644 --- a/src/main/java/electrosphere/data/block/fab/StructureMetadata.java +++ b/src/main/java/electrosphere/data/block/fab/StructureMetadata.java @@ -3,25 +3,13 @@ package electrosphere.data.block.fab; import java.util.LinkedList; import java.util.List; -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; /** * Structure data */ public class StructureMetadata { - /** - * Maximum radius of room in blocks - */ - public static final int MAX_ROOM_SIZE = 20; - /** * The bounding area of the structure */ @@ -44,80 +32,6 @@ public class StructureMetadata { return rVal; } - /** - * 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 void computeRoomsFromSelection(){ - 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 localMaximums = new LinkedList(); - 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 : rooms){ - 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); - rooms.add(new RoomMetadata(roomArea)); - } - - } - /** * Gets the bounding area * @return The bounding area