block area selection control
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-26 00:16:36 -04:00
parent f7c6208a2a
commit 20c53b151b
8 changed files with 174 additions and 1 deletions

View File

@ -1536,6 +1536,9 @@ Audio on placing blocks
Audio on placing/removing voxels
Debounce item usage activations
Variable block editing size
Increase block cursor size
Block area selection

View File

@ -69,6 +69,11 @@ public class BlockChunkData {
*/
public static final int LOD_LOWEST_RES = LOD_SIXTEENTH_RES;
/**
* An empty block
*/
public static final short BLOCK_TYPE_EMPTY = 0;
/**
* The type of block at a given position

View File

@ -0,0 +1,75 @@
package electrosphere.client.block;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.controls.cursor.CursorState;
import electrosphere.engine.Globals;
/**
* Class for selecting blocks on the client
*/
public class ClientBlockSelection {
/**
* Selects all blocks on the client
*/
public static void selectAllBlocks(){
Vector3d minPos = new Vector3d();
Vector3d maxPos = new Vector3d();
Vector3i minVoxelPos = new Vector3i();
Vector3i maxVoxelPos = new Vector3i();
Vector3i chunkPos = new Vector3i();
boolean encountered = false;
for(int x = 0; x < Globals.clientWorldData.getWorldDiscreteSize(); x++){
for(int y = 0; y < Globals.clientWorldData.getWorldDiscreteSize(); y++){
for(int z = 0; z < Globals.clientWorldData.getWorldDiscreteSize(); z++){
chunkPos = new Vector3i(x,y,z);
BlockChunkData blockChunkData = Globals.clientBlockManager.getChunkDataAtWorldPoint(chunkPos, 0);
if(blockChunkData.getHomogenousValue() == BlockChunkData.BLOCK_TYPE_EMPTY){
continue;
}
boolean foundVoxel = false;
for(int i = 0; i < BlockChunkData.CHUNK_DATA_WIDTH; i++){
for(int j = 0; j < BlockChunkData.CHUNK_DATA_WIDTH; j++){
for(int k = 0; k < BlockChunkData.CHUNK_DATA_WIDTH; k++){
if(blockChunkData.getType(i, j, k) == BlockChunkData.BLOCK_TYPE_EMPTY){
continue;
}
if(!foundVoxel){
foundVoxel = true;
minVoxelPos.set(i,j,k);
maxVoxelPos.set(i+1,j+1,k+1);
} else {
minVoxelPos.min(new Vector3i(i,j,k));
maxVoxelPos.max(new Vector3i(i+1,j+1,k+1));
}
}
}
}
Vector3d localMin = Globals.clientWorldData.convertBlockToRealSpace(chunkPos, minVoxelPos);
Vector3d localMax = Globals.clientWorldData.convertBlockToRealSpace(chunkPos, maxVoxelPos);
if(!encountered){
encountered = true;
minPos.set(localMin);
maxPos.set(localMax);
} else {
minPos.min(localMin);
maxPos.max(localMax);
}
}
}
}
CursorState.selectRectangularArea(minPos, maxPos);
}
}

View File

@ -215,4 +215,28 @@ public class ClientWorldData {
);
}
/**
* Converts a block position to a real position
* @param chunkPos The position of the chunk
* @param blockPos The position of the block within the chunk
* @return The real position corresponding to the block's position
*/
public double convertBlockToRealSpace(int chunkPos, int blockPos){
return ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET * chunkPos + BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockPos;
}
/**
* Converts a block position to a real position
* @param chunkPos The chunk's position
* @param blockPos The block's position
* @return The real position
*/
public Vector3d convertBlockToRealSpace(Vector3i chunkPos, Vector3i blockPos){
return new Vector3d(
convertBlockToRealSpace(chunkPos.x, blockPos.x),
convertBlockToRealSpace(chunkPos.y, blockPos.y),
convertBlockToRealSpace(chunkPos.z, blockPos.z)
);
}
}

View File

@ -0,0 +1,20 @@
package electrosphere.client.ui.menu.editor;
import electrosphere.client.block.ClientBlockSelection;
import imgui.ImGui;
/**
* Class for drawing the area tab of the editor window
*/
public class ImGuiAreaTab {
/**
* Draws the area tab
*/
protected static void draw(){
if(ImGui.button("Select all voxels")){
ClientBlockSelection.selectAllBlocks();
}
}
}

View File

@ -64,6 +64,10 @@ public class ImGuiEditorWindows {
ImGui.text("hierarchy controls here");
ImGui.endTabItem();
}
if(ImGui.beginTabItem("Areas")){
ImGuiAreaTab.draw();
ImGui.endTabItem();
}
ImGui.endTabBar();
}

View File

@ -34,6 +34,11 @@ public class CursorState {
*/
public static final String CURSOR_BLOCK_TOKEN = "CURSOR_BLOCK";
/**
* Token for displaying a block area selection cursor
*/
public static final String CURSOR_AREA_TOKEN = "CURSOR_AREA";
/**
* Minimum size of the block cursor
*/
@ -47,7 +52,7 @@ public class CursorState {
/**
* The scale multiplier for scaling the block cursor
*/
private static final float BLOCK_CURSOR_SCALE_MULTIPLIER = 0.2f;
private static final float BLOCK_CURSOR_SCALE_MULTIPLIER = 0.25f;
/**
* Size of blocks to edit
@ -75,6 +80,15 @@ public class CursorState {
DrawableUtils.makeEntityTransparent(Globals.playerBlockCursor);
EntityUtils.getScale(Globals.playerBlockCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
//player's area cursor
Globals.playerAreaCursor = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(Globals.playerAreaCursor, AssetDataStrings.UNITCUBE);
Actor areaCursorActor = EntityUtils.getActor(Globals.playerAreaCursor);
areaCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
DrawableUtils.makeEntityTransparent(Globals.playerAreaCursor);
EntityUtils.getScale(Globals.playerAreaCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE);
}
/**
@ -107,6 +121,7 @@ public class CursorState {
*/
public static void makeRealVisible(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerCursor, EntityTags.DRAWABLE);
}
@ -115,15 +130,41 @@ public class CursorState {
*/
public static void makeBlockVisible(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
}
/**
* Makes the area position cursor visible
*/
public static void makeAreaVisible(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerAreaCursor, EntityTags.DRAWABLE);
}
/**
* Hides the cursor
*/
public static void hide(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE);
}
/**
* Selects a rectangular area
* @param startPos The start position of the area
* @param endPos The end position of the area
*/
public static void selectRectangularArea(Vector3d startPos, Vector3d endPos){
Vector3d center = new Vector3d(startPos).add(endPos).mul(0.5f);
Vector3d scale = new Vector3d(startPos).sub(endPos).absolute();
EntityCreationUtils.makeEntityDrawable(Globals.playerAreaCursor, AssetDataStrings.UNITCUBE);
Actor areaCursorActor = EntityUtils.getActor(Globals.playerAreaCursor);
areaCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
EntityUtils.getPosition(Globals.playerAreaCursor).set(center);
EntityUtils.getScale(Globals.playerAreaCursor).set(scale);
}
/**

View File

@ -407,6 +407,7 @@ public class Globals {
//the player in world cursor
public static Entity playerCursor;
public static Entity playerBlockCursor;
public static Entity playerAreaCursor;
//the creature the player camera will orbit and will receive controlHandler movementTree updates
public static Entity playerEntity;