371 lines
15 KiB
Java
371 lines
15 KiB
Java
package electrosphere.client.interact.select;
|
|
|
|
import org.joml.Vector3d;
|
|
import org.joml.Vector3i;
|
|
|
|
import electrosphere.client.block.BlockChunkData;
|
|
import electrosphere.engine.Globals;
|
|
|
|
/**
|
|
* An area of space that is selected by the client
|
|
*/
|
|
public class AreaSelection {
|
|
|
|
/**
|
|
* The type of selection
|
|
*/
|
|
public static enum AreaSelectionType {
|
|
/**
|
|
* A rectangle
|
|
*/
|
|
RECTANGULAR,
|
|
}
|
|
|
|
/**
|
|
* Default radius to select
|
|
*/
|
|
public static final int DEFAULT_SELECTION_RADIUS = 10;
|
|
|
|
/**
|
|
* The type of selection
|
|
*/
|
|
private AreaSelectionType type;
|
|
|
|
/**
|
|
* The start point of the rectangular selection
|
|
*/
|
|
private Vector3d rectStart;
|
|
|
|
/**
|
|
* The end point of the rectangular selection
|
|
*/
|
|
private Vector3d rectEnd;
|
|
|
|
/**
|
|
* Creates a rectangular selection
|
|
* @param start The start point
|
|
* @param end The end point
|
|
* @return The selection
|
|
*/
|
|
public static AreaSelection createRect(Vector3d start, Vector3d end){
|
|
if(start.x > end.x){
|
|
throw new Error("Start x is less than end x! " + start.x + " " + end.x);
|
|
}
|
|
if(start.y > end.y){
|
|
throw new Error("Start y is less than end y! " + start.y + " " + end.y);
|
|
}
|
|
if(start.z > end.z){
|
|
throw new Error("Start y is less than end y! " + start.z + " " + end.z);
|
|
}
|
|
AreaSelection rVal = new AreaSelection();
|
|
rVal.type = AreaSelectionType.RECTANGULAR;
|
|
rVal.rectStart = start;
|
|
rVal.rectEnd = end;
|
|
return rVal;
|
|
}
|
|
|
|
/**
|
|
* Calculates the rectangular area of empty voxels in the block chunks starting at a given position
|
|
* @param chunkPos The chunk position to start from
|
|
* @param blockPos The block position to start from
|
|
* @param maxRadius The maximum radius to expand the area to
|
|
* @return The AreaSelection
|
|
*/
|
|
public static AreaSelection selectRectangularBlockCavity(Vector3i chunkPos, Vector3i blockPos, int maxRadius){
|
|
AreaSelection rVal = null;
|
|
|
|
Vector3i startOffset = new Vector3i(0,0,0);
|
|
Vector3i endOffset = new Vector3i(1,1,1);
|
|
int increment = 0;
|
|
boolean expandPositiveX = true;
|
|
boolean expandPositiveY = true;
|
|
boolean expandPositiveZ = true;
|
|
boolean expandNegativeX = true;
|
|
boolean expandNegativeY = true;
|
|
boolean expandNegativeZ = true;
|
|
Vector3i currVoxelPos = new Vector3i();
|
|
Vector3i currChunkPos = new Vector3i();
|
|
while(
|
|
startOffset.x > -maxRadius && startOffset.y > -maxRadius && startOffset.z > -maxRadius &&
|
|
endOffset.x < maxRadius && endOffset.y < maxRadius && endOffset.z < maxRadius &&
|
|
(
|
|
expandPositiveX || expandPositiveY || expandPositiveZ ||
|
|
expandNegativeX || expandNegativeY || expandNegativeZ
|
|
)){
|
|
increment++;
|
|
switch(increment % 6){
|
|
case 0: {
|
|
if(expandPositiveX){
|
|
endOffset.x = endOffset.x + 1;
|
|
} else {
|
|
continue;
|
|
}
|
|
} break;
|
|
case 1: {
|
|
if(expandPositiveY){
|
|
endOffset.y = endOffset.y + 1;
|
|
} else {
|
|
continue;
|
|
}
|
|
} break;
|
|
case 2: {
|
|
if(expandPositiveZ){
|
|
endOffset.z = endOffset.z + 1;
|
|
} else {
|
|
continue;
|
|
}
|
|
} break;
|
|
case 3: {
|
|
if(expandNegativeX){
|
|
startOffset.x = startOffset.x - 1;
|
|
} else {
|
|
continue;
|
|
}
|
|
} break;
|
|
case 4: {
|
|
if(expandNegativeY){
|
|
startOffset.y = startOffset.y - 1;
|
|
} else {
|
|
continue;
|
|
}
|
|
} break;
|
|
case 5: {
|
|
if(expandNegativeZ){
|
|
startOffset.z = startOffset.z - 1;
|
|
} else {
|
|
continue;
|
|
}
|
|
} break;
|
|
}
|
|
for(int x = startOffset.x; x < endOffset.x; x++){
|
|
for(int y = startOffset.y; y < endOffset.y; y++){
|
|
for(int z = startOffset.z; z < endOffset.z; z++){
|
|
currVoxelPos.set(blockPos).add(x,y,z);
|
|
currChunkPos.set(chunkPos).add(
|
|
currVoxelPos.x / BlockChunkData.CHUNK_DATA_WIDTH,
|
|
currVoxelPos.y / BlockChunkData.CHUNK_DATA_WIDTH,
|
|
currVoxelPos.z / BlockChunkData.CHUNK_DATA_WIDTH
|
|
);
|
|
currVoxelPos.set(
|
|
currVoxelPos.x % BlockChunkData.CHUNK_DATA_WIDTH,
|
|
currVoxelPos.y % BlockChunkData.CHUNK_DATA_WIDTH,
|
|
currVoxelPos.z % BlockChunkData.CHUNK_DATA_WIDTH
|
|
);
|
|
if(!Globals.clientWorldData.chunkInBounds(currChunkPos)){
|
|
switch(increment % 6){
|
|
case 0: {
|
|
if(expandPositiveX){
|
|
expandPositiveX = false;
|
|
if(endOffset.x > 1){
|
|
endOffset.x--;
|
|
}
|
|
}
|
|
} break;
|
|
case 1: {
|
|
if(expandPositiveY){
|
|
expandPositiveY = false;
|
|
if(endOffset.y > 1){
|
|
endOffset.y--;
|
|
}
|
|
}
|
|
} break;
|
|
case 2: {
|
|
if(expandPositiveZ){
|
|
expandPositiveZ = false;
|
|
if(endOffset.z > 1){
|
|
endOffset.z--;
|
|
}
|
|
}
|
|
} break;
|
|
case 3: {
|
|
if(expandNegativeX){
|
|
expandNegativeX = false;
|
|
if(startOffset.x < 0){
|
|
startOffset.x++;
|
|
}
|
|
}
|
|
} break;
|
|
case 4: {
|
|
if(expandNegativeY){
|
|
expandNegativeY = false;
|
|
if(startOffset.y < 0){
|
|
startOffset.y++;
|
|
}
|
|
}
|
|
} break;
|
|
case 5: {
|
|
if(expandNegativeZ){
|
|
expandNegativeZ = false;
|
|
if(startOffset.z < 0){
|
|
startOffset.z++;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
continue;
|
|
}
|
|
BlockChunkData chunkData = Globals.clientBlockManager.getChunkDataAtWorldPoint(currChunkPos, BlockChunkData.LOD_FULL_RES);
|
|
if(chunkData == null){
|
|
switch(increment % 6){
|
|
case 0: {
|
|
if(expandPositiveX){
|
|
expandPositiveX = false;
|
|
if(endOffset.x > 1){
|
|
endOffset.x--;
|
|
}
|
|
}
|
|
} break;
|
|
case 1: {
|
|
if(expandPositiveY){
|
|
expandPositiveY = false;
|
|
if(endOffset.y > 1){
|
|
endOffset.y--;
|
|
}
|
|
}
|
|
} break;
|
|
case 2: {
|
|
if(expandPositiveZ){
|
|
expandPositiveZ = false;
|
|
if(endOffset.z > 1){
|
|
endOffset.z--;
|
|
}
|
|
}
|
|
} break;
|
|
case 3: {
|
|
if(expandNegativeX){
|
|
expandNegativeX = false;
|
|
if(startOffset.x < 0){
|
|
startOffset.x++;
|
|
}
|
|
}
|
|
} break;
|
|
case 4: {
|
|
if(expandNegativeY){
|
|
expandNegativeY = false;
|
|
if(startOffset.y < 0){
|
|
startOffset.y++;
|
|
}
|
|
}
|
|
} break;
|
|
case 5: {
|
|
if(expandNegativeZ){
|
|
expandNegativeZ = false;
|
|
if(startOffset.z < 0){
|
|
startOffset.z++;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
continue;
|
|
}
|
|
while(currVoxelPos.x < 0){
|
|
currVoxelPos.x = currVoxelPos.x + BlockChunkData.CHUNK_DATA_WIDTH;
|
|
}
|
|
while(currVoxelPos.y < 0){
|
|
currVoxelPos.y = currVoxelPos.y + BlockChunkData.CHUNK_DATA_WIDTH;
|
|
}
|
|
while(currVoxelPos.z < 0){
|
|
currVoxelPos.z = currVoxelPos.z + BlockChunkData.CHUNK_DATA_WIDTH;
|
|
}
|
|
if(!chunkData.isEmpty(currVoxelPos)){
|
|
switch(increment % 6){
|
|
case 0: {
|
|
if(expandPositiveX){
|
|
expandPositiveX = false;
|
|
if(endOffset.x > 1){
|
|
endOffset.x--;
|
|
}
|
|
}
|
|
} break;
|
|
case 1: {
|
|
if(expandPositiveY){
|
|
expandPositiveY = false;
|
|
if(endOffset.y > 1){
|
|
endOffset.y--;
|
|
}
|
|
}
|
|
} break;
|
|
case 2: {
|
|
if(expandPositiveZ){
|
|
expandPositiveZ = false;
|
|
if(endOffset.z > 1){
|
|
endOffset.z--;
|
|
}
|
|
}
|
|
} break;
|
|
case 3: {
|
|
if(expandNegativeX){
|
|
expandNegativeX = false;
|
|
if(startOffset.x < 0){
|
|
startOffset.x++;
|
|
}
|
|
}
|
|
} break;
|
|
case 4: {
|
|
if(expandNegativeY){
|
|
expandNegativeY = false;
|
|
if(startOffset.y < 0){
|
|
startOffset.y++;
|
|
}
|
|
}
|
|
} break;
|
|
case 5: {
|
|
if(expandNegativeZ){
|
|
expandNegativeZ = false;
|
|
if(startOffset.z < 0){
|
|
startOffset.z++;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Vector3d startPos = new Vector3d(Globals.clientWorldData.convertBlockToRealSpace(chunkPos, blockPos))
|
|
.add(
|
|
startOffset.x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
|
startOffset.y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
|
startOffset.z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
|
);
|
|
Vector3d endPos = new Vector3d(Globals.clientWorldData.convertBlockToRealSpace(chunkPos, blockPos))
|
|
.add(
|
|
endOffset.x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
|
endOffset.y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
|
endOffset.z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
|
);
|
|
|
|
rVal = AreaSelection.createRect(startPos, endPos);
|
|
|
|
return rVal;
|
|
}
|
|
|
|
/**
|
|
* Gets the type of area
|
|
* @return The type of area
|
|
*/
|
|
public AreaSelectionType getType() {
|
|
return type;
|
|
}
|
|
|
|
/**
|
|
* Gets the start point of the rectangular selection
|
|
* @return The start point
|
|
*/
|
|
public Vector3d getRectStart() {
|
|
return rectStart;
|
|
}
|
|
|
|
/**
|
|
* Gets the end point of the rectangular selection
|
|
* @return The end point
|
|
*/
|
|
public Vector3d getRectEnd() {
|
|
return rectEnd;
|
|
}
|
|
|
|
|
|
}
|