room detection within structures
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
d656d75535
commit
2fc984c3f1
@ -1849,6 +1849,7 @@ Fix caching with deleted source files
|
||||
Proof of concept of ui button calling engine code
|
||||
Script engine direct access to joml vectors
|
||||
Script engine passing objects back into methods successfully
|
||||
Room detection within structures
|
||||
|
||||
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.client.block.ClientBlockManager;
|
||||
import electrosphere.client.block.StructureData;
|
||||
import electrosphere.client.block.cells.ClientBlockCellManager;
|
||||
import electrosphere.client.chemistry.ClientChemistryCollisionCallback;
|
||||
import electrosphere.client.entity.character.ClientCharacterManager;
|
||||
@ -187,6 +188,11 @@ public class ClientState {
|
||||
*/
|
||||
public int openInventoriesCount = 0;
|
||||
|
||||
/**
|
||||
* The currently selected structure's data
|
||||
*/
|
||||
public StructureData currentStructureData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
package electrosphere.client.block;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.client.interact.select.AreaSelection;
|
||||
import electrosphere.client.interact.select.AreaSelection.AreaSelectionType;
|
||||
import electrosphere.client.scene.ClientWorldData;
|
||||
import electrosphere.data.block.BlockFab;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.util.math.HashUtils;
|
||||
|
||||
/**
|
||||
* Class for selecting blocks on the client
|
||||
@ -128,4 +133,100 @@ public class ClientBlockSelection {
|
||||
return fab;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 the SDF of distance from nearest solid block for the selected area
|
||||
* @param boundingArea The bounding area
|
||||
* @return The sdf
|
||||
*/
|
||||
public static int[][][] computeCavitySDF(AreaSelection boundingArea){
|
||||
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);
|
||||
|
||||
Vector3d currPos = new Vector3d();
|
||||
|
||||
//compute dist field
|
||||
int[][][] distField = new int[dimX][dimY][dimZ];
|
||||
|
||||
|
||||
//sets for breadth-first search
|
||||
LinkedList<Long> openSet = new LinkedList<Long>();
|
||||
Map<Long,Integer> closedSet = new HashMap<Long,Integer>();
|
||||
|
||||
//enqueue all positions
|
||||
for(int x = 0; x < dimX; x++){
|
||||
for(int y = 0; y < dimY; y++){
|
||||
for(int z = 0; z < dimZ; z++){
|
||||
currPos.set(boundingArea.getRectStart()).add(
|
||||
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||
);
|
||||
Vector3i chunkPos = ClientWorldData.convertRealToChunkSpace(currPos);
|
||||
Vector3i blockPos = ClientWorldData.convertRealToLocalBlockSpace(currPos);
|
||||
BlockChunkData chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(chunkPos, BlockChunkData.LOD_FULL_RES);
|
||||
if(chunkData == null){
|
||||
throw new Error("Missing chunk! " + chunkPos);
|
||||
}
|
||||
short type = chunkData.getType(blockPos.x, blockPos.y, blockPos.z);
|
||||
if(type == BlockChunkData.BLOCK_TYPE_EMPTY){
|
||||
} else {
|
||||
openSet.add(HashUtils.hashIVec(x, y, z));
|
||||
closedSet.put(HashUtils.hashIVec(x, y, z),1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//error check initialization
|
||||
if(closedSet.size() < 1){
|
||||
throw new Error("Failed to detect empty chunks!");
|
||||
}
|
||||
|
||||
//search
|
||||
while(openSet.size() > 0){
|
||||
Long hash = openSet.poll();
|
||||
int x = HashUtils.unhashIVec(hash, HashUtils.UNHASH_COMPONENT_X);
|
||||
int y = HashUtils.unhashIVec(hash, HashUtils.UNHASH_COMPONENT_Y);
|
||||
int z = HashUtils.unhashIVec(hash, HashUtils.UNHASH_COMPONENT_Z);
|
||||
int currVal = closedSet.get(hash);
|
||||
|
||||
for(int[] dir : NEIGHBORS) {
|
||||
int nx = x + dir[0];
|
||||
int ny = y + dir[1];
|
||||
int nz = z + dir[2];
|
||||
|
||||
if(
|
||||
nx >= 0 && ny >= 0 && nz >= 0 &&
|
||||
nx < dimX && ny < dimY && nz < dimZ
|
||||
){
|
||||
long nHash = HashUtils.hashIVec(nx, ny, nz);
|
||||
if(!closedSet.containsKey(nHash)){
|
||||
//evaluate all neighbors of this neighbor
|
||||
openSet.add(nHash);
|
||||
//store dist of neighbor
|
||||
int neighborVal = currVal + 1;
|
||||
closedSet.put(nHash, neighborVal);
|
||||
distField[nx][ny][nz] = neighborVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distField;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
136
src/main/java/electrosphere/client/block/StructureData.java
Normal file
136
src/main/java/electrosphere/client/block/StructureData.java
Normal file
@ -0,0 +1,136 @@
|
||||
package electrosphere.client.block;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.client.interact.select.AreaSelection;
|
||||
import electrosphere.client.interact.select.AreaSelection.AreaSelectionType;
|
||||
import electrosphere.client.scene.ClientWorldData;
|
||||
|
||||
/**
|
||||
* Structure data
|
||||
*/
|
||||
public class StructureData {
|
||||
|
||||
/**
|
||||
* Maximum radius of room in blocks
|
||||
*/
|
||||
public static final int MAX_ROOM_SIZE = 20;
|
||||
|
||||
/**
|
||||
* The bounding area of the structure
|
||||
*/
|
||||
AreaSelection boundingArea;
|
||||
|
||||
/**
|
||||
* The rooms defined within the structure
|
||||
*/
|
||||
List<AreaSelection> rooms = new LinkedList<AreaSelection>();
|
||||
|
||||
|
||||
/**
|
||||
* Creatures a structure data object
|
||||
* @param boundingArea The bounding area
|
||||
* @return The structure data
|
||||
*/
|
||||
public static StructureData create(AreaSelection boundingArea){
|
||||
StructureData rVal = new StructureData();
|
||||
rVal.boundingArea = boundingArea;
|
||||
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<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(AreaSelection room : rooms){
|
||||
if(room.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(roomArea);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bounding area
|
||||
* @return The bounding area
|
||||
*/
|
||||
public AreaSelection getBoundingArea(){
|
||||
return boundingArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of areas that encompass rooms
|
||||
* @return The list of areas
|
||||
*/
|
||||
public List<AreaSelection> getRooms(){
|
||||
return rooms;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package electrosphere.client.interact.select;
|
||||
|
||||
import org.graalvm.polyglot.HostAccess.Export;
|
||||
import org.joml.AABBd;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
@ -42,6 +43,11 @@ public class AreaSelection {
|
||||
*/
|
||||
private Vector3d rectEnd;
|
||||
|
||||
/**
|
||||
* The AABB of the area selection
|
||||
*/
|
||||
private AABBd aabb;
|
||||
|
||||
/**
|
||||
* Creates a rectangular selection
|
||||
* @param start The start point
|
||||
@ -62,6 +68,7 @@ public class AreaSelection {
|
||||
rVal.type = AreaSelectionType.RECTANGULAR;
|
||||
rVal.rectStart = start;
|
||||
rVal.rectEnd = end;
|
||||
rVal.aabb = new AABBd(start, end);
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@ -369,4 +376,13 @@ public class AreaSelection {
|
||||
return rectEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the area contains a point
|
||||
* @param point The point
|
||||
* @return true if it contains the point, false otherwise
|
||||
*/
|
||||
public boolean containsPoint(Vector3d point){
|
||||
return aabb.testPoint(point);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import java.io.File;
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.client.block.ClientBlockSelection;
|
||||
import electrosphere.client.block.StructureData;
|
||||
import electrosphere.client.interact.select.AreaSelection;
|
||||
import electrosphere.data.block.BlockFab;
|
||||
import electrosphere.data.block.BlockFabMetadata;
|
||||
@ -33,6 +34,14 @@ public class ImGuiStructureTab {
|
||||
}
|
||||
} else {
|
||||
BlockFab currentFab = Globals.clientState.clientLevelEditorData.getCurrentFab();
|
||||
if(Globals.clientState.currentStructureData == null){
|
||||
if(ImGui.button("Create Structure Data")){
|
||||
Globals.clientState.currentStructureData = StructureData.create(Globals.cursorState.getAreaSelection());
|
||||
}
|
||||
}
|
||||
if(Globals.clientState.currentStructureData != null && ImGui.button("Calculate Rooms")){
|
||||
Globals.clientState.currentStructureData.computeRoomsFromSelection();
|
||||
}
|
||||
if(ImGui.button("Convert current selection to room")){
|
||||
AreaSelection currentSelection = Globals.cursorState.getAreaSelection();
|
||||
if(currentSelection != null){
|
||||
|
||||
@ -13,6 +13,7 @@ import org.ode4j.ode.DSphere;
|
||||
|
||||
import electrosphere.client.block.BlockChunkData;
|
||||
import electrosphere.client.entity.camera.CameraEntityUtils;
|
||||
import electrosphere.client.interact.select.AreaSelection;
|
||||
import electrosphere.collision.CollisionEngine;
|
||||
import electrosphere.collision.PhysicsUtils;
|
||||
import electrosphere.collision.collidable.Collidable;
|
||||
@ -76,121 +77,144 @@ public class DebugContentPipeline implements RenderPipeline {
|
||||
Matrix4d modelTransformMatrix = new Matrix4d();
|
||||
|
||||
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawCollisionSpheresClient()){
|
||||
Model hitboxModel;
|
||||
for(HitboxCollectionState hitboxState : Globals.clientState.clientSceneWrapper.getHitboxManager().getAllHitboxes()){
|
||||
for(DGeom geom : hitboxState.getGeometries()){
|
||||
if(geom instanceof DSphere){
|
||||
DSphere sphereView = (DSphere)geom;
|
||||
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
|
||||
if((hitboxModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITSPHERE)) != null){
|
||||
//set color based on collision status, type, etc
|
||||
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = PhysicsUtils.odeVecToJomlVec(sphereView.getPosition());
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
modelTransformMatrix.scale(sphereView.getRadius() * 2);
|
||||
hitboxModel.setModelMatrix(modelTransformMatrix);
|
||||
hitboxModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
if(geom instanceof DCapsule){
|
||||
DCapsule capsuleView = (DCapsule)geom;
|
||||
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
|
||||
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitcapsule.glb")) != null){
|
||||
//set color based on collision status, type, etc
|
||||
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = PhysicsUtils.odeVecToJomlVec(capsuleView.getPosition());
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
//since you're directly accessing the quat from the body, need to adjust it to be in the correct orientation
|
||||
modelTransformMatrix.rotate(PhysicsUtils.odeQuatToJomlQuat(capsuleView.getQuaternion()).mul(new Quaterniond(0.707,0,0,0.707)));
|
||||
//the ode4j capsule's end caps are always at least radius length, the length only controls the distance between the two caps.
|
||||
//unfortunately that won't be easy to replicate with rendering tech currently; instead, run logic below
|
||||
double radius = capsuleView.getRadius();
|
||||
double length = capsuleView.getLength();
|
||||
if(length < radius) length = radius;
|
||||
modelTransformMatrix.scale(radius,length,radius);
|
||||
hitboxModel.setModelMatrix(modelTransformMatrix);
|
||||
hitboxModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
}
|
||||
DebugContentPipeline.renderHitboxes(openGLState, renderPipelineState, modelTransformMatrix, hitboxState);
|
||||
}
|
||||
}
|
||||
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawCollisionSpheresServer()){
|
||||
Model hitboxModel;
|
||||
int serverIdForClientEntity = Globals.clientState.clientSceneWrapper.mapClientToServerId(Globals.clientState.playerEntity.getId());
|
||||
Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
|
||||
Realm playerRealm = Globals.serverState.realmManager.getEntityRealm(serverPlayerEntity);
|
||||
List<HitboxCollectionState> hitboxStates = new LinkedList<HitboxCollectionState>(playerRealm.getHitboxManager().getAllHitboxes());
|
||||
for(HitboxCollectionState hitboxState : hitboxStates){
|
||||
for(DGeom geom : hitboxState.getGeometries()){
|
||||
if(geom instanceof DSphere){
|
||||
DSphere sphereView = (DSphere)geom;
|
||||
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
|
||||
if((hitboxModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITSPHERE)) != null){
|
||||
//set color based on collision status, type, etc
|
||||
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = PhysicsUtils.odeVecToJomlVec(sphereView.getPosition());
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
modelTransformMatrix.scale(sphereView.getRadius() * 2);
|
||||
hitboxModel.setModelMatrix(modelTransformMatrix);
|
||||
hitboxModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
if(geom instanceof DCapsule){
|
||||
DCapsule capsuleView = (DCapsule)geom;
|
||||
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
|
||||
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitcapsule.glb")) != null){
|
||||
//set color based on collision status, type, etc
|
||||
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = PhysicsUtils.odeVecToJomlVec(capsuleView.getPosition());
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
//since you're directly accessing the quat from the body, need to adjust it to be in the correct orientation
|
||||
modelTransformMatrix.rotate(PhysicsUtils.odeQuatToJomlQuat(capsuleView.getQuaternion()).mul(new Quaterniond(0.707,0,0,0.707)));
|
||||
//the ode4j capsule's end caps are always at least radius length, the length only controls the distance between the two caps.
|
||||
//unfortunately that won't be easy to replicate with rendering tech currently; instead, run logic below
|
||||
double radius = capsuleView.getRadius();
|
||||
double length = capsuleView.getLength();
|
||||
if(length < radius) length = radius;
|
||||
modelTransformMatrix.scale(radius,length,radius);
|
||||
hitboxModel.setModelMatrix(modelTransformMatrix);
|
||||
hitboxModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
}
|
||||
DebugContentPipeline.renderHitboxes(openGLState, renderPipelineState, modelTransformMatrix, hitboxState);
|
||||
}
|
||||
}
|
||||
|
||||
if(Globals.gameConfigCurrent.getSettings().graphicsDebugDrawPhysicsObjects()){
|
||||
Model physicsGraphicsModel;
|
||||
CollisionEngine engine = Globals.clientState.clientSceneWrapper.getCollisionEngine();
|
||||
for(Collidable collidable : engine.getCollidables()){
|
||||
Entity physicsEntity = collidable.getParent();
|
||||
if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE) != null){
|
||||
CollidableTemplate template = (CollidableTemplate)physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
|
||||
DebugContentPipeline.renderCollidable(openGLState, renderPipelineState, modelTransformMatrix, physicsEntity, template);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Globals.clientState.currentStructureData != null){
|
||||
if(Globals.clientState.currentStructureData.getBoundingArea() != null){
|
||||
DebugContentPipeline.renderAreaSelection(
|
||||
openGLState, renderPipelineState, modelTransformMatrix,
|
||||
Globals.clientState.currentStructureData.getBoundingArea(), AssetDataStrings.TEXTURE_RED_TRANSPARENT
|
||||
);
|
||||
if(Globals.clientState.currentStructureData.getRooms() != null){
|
||||
for(AreaSelection roomArea : Globals.clientState.currentStructureData.getRooms()){
|
||||
DebugContentPipeline.renderAreaSelection(
|
||||
openGLState, renderPipelineState, modelTransformMatrix,
|
||||
roomArea, AssetDataStrings.TEXTURE_TEAL_TRANSPARENT
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//Draw grid alignment data
|
||||
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawGridAlignment()){
|
||||
Model physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE);
|
||||
for(Entity entity : Globals.clientState.clientSceneWrapper.getScene().getEntityList()){
|
||||
CommonEntityType data = CommonEntityUtils.getCommonData(entity);
|
||||
if(data == null){
|
||||
continue;
|
||||
}
|
||||
if(data.getGridAlignedData() != null){
|
||||
GridAlignedData gridAlignedData = data.getGridAlignedData();
|
||||
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = EntityUtils.getPosition(entity);
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).add(0,gridAlignedData.getHeight() * BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0f,0).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
modelTransformMatrix.rotate(EntityUtils.getRotation(entity));
|
||||
modelTransformMatrix.scale(
|
||||
gridAlignedData.getWidth() * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
gridAlignedData.getHeight() * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
gridAlignedData.getLength() * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||
);
|
||||
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
|
||||
physicsGraphicsModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//update pipeline state to use mats again
|
||||
renderPipelineState.setUseMaterial(true);
|
||||
|
||||
if(Globals.gameConfigCurrent.getSettings().graphicsDebugDrawNavmesh()){
|
||||
throw new Error("Not yet implemented!");
|
||||
}
|
||||
|
||||
debugBonesPipeline.render(openGLState, renderPipelineState);
|
||||
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color texture to use to draw a hitbox
|
||||
* @param shapeStatus The hitbox status
|
||||
* @param data The hitbox data
|
||||
* @return The texture path to use
|
||||
*/
|
||||
private static String getHitboxColor(HitboxState shapeStatus, HitboxData data){
|
||||
switch(data.getType()){
|
||||
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
|
||||
if(shapeStatus.getHadCollision()){
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
}
|
||||
if(shapeStatus.isActive()){
|
||||
return "Textures/transparent_blue.png";
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
case HitboxData.HITBOX_TYPE_HIT:
|
||||
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
|
||||
if(shapeStatus.getHadCollision()){
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
}
|
||||
if(shapeStatus.isActive()){
|
||||
if(shapeStatus.isBlockOverride()){
|
||||
return "Textures/transparent_blue.png";
|
||||
}
|
||||
return "Textures/transparent_red.png";
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
case HitboxData.HITBOX_TYPE_HURT:
|
||||
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
|
||||
if(shapeStatus.getHadCollision()){
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a collidable
|
||||
* @param openGLState The opengl state
|
||||
* @param renderPipelineState The render pipeline state
|
||||
* @param modelTransformMatrix The model transform matrix
|
||||
* @param physicsEntity The entity
|
||||
* @param template The template
|
||||
*/
|
||||
static void renderCollidable(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Entity physicsEntity, CollidableTemplate template){
|
||||
Model physicsGraphicsModel;
|
||||
if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE) != null){
|
||||
switch(template.getType()){
|
||||
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
|
||||
if((physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER)) != null){
|
||||
@ -254,91 +278,89 @@ public class DebugContentPipeline implements RenderPipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//Draw grid alignment data
|
||||
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawGridAlignment()){
|
||||
Model physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE);
|
||||
for(Entity entity : Globals.clientState.clientSceneWrapper.getScene().getEntityList()){
|
||||
CommonEntityType data = CommonEntityUtils.getCommonData(entity);
|
||||
if(data == null){
|
||||
continue;
|
||||
}
|
||||
if(data.getGridAlignedData() != null){
|
||||
GridAlignedData gridAlignedData = data.getGridAlignedData();
|
||||
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
|
||||
/**
|
||||
* Renders a hitbox collection state
|
||||
* @param openGLState The opengl state
|
||||
* @param renderPipelineState The render pipeline state
|
||||
* @param modelTransformMatrix The model transform matrix
|
||||
* @param hitboxState The hitbox collection state
|
||||
*/
|
||||
static void renderHitboxes(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, HitboxCollectionState hitboxState){
|
||||
Model hitboxModel;
|
||||
for(DGeom geom : hitboxState.getGeometries()){
|
||||
if(geom instanceof DSphere){
|
||||
DSphere sphereView = (DSphere)geom;
|
||||
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
|
||||
if((hitboxModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITSPHERE)) != null){
|
||||
//set color based on collision status, type, etc
|
||||
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = EntityUtils.getPosition(entity);
|
||||
Vector3d position = PhysicsUtils.odeVecToJomlVec(sphereView.getPosition());
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).add(0,gridAlignedData.getHeight() * BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0f,0).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
modelTransformMatrix.rotate(EntityUtils.getRotation(entity));
|
||||
modelTransformMatrix.scale(
|
||||
gridAlignedData.getWidth() * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
gridAlignedData.getHeight() * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
gridAlignedData.getLength() * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||
);
|
||||
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
|
||||
physicsGraphicsModel.draw(renderPipelineState,openGLState);
|
||||
modelTransformMatrix.scale(sphereView.getRadius() * 2);
|
||||
hitboxModel.setModelMatrix(modelTransformMatrix);
|
||||
hitboxModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
if(geom instanceof DCapsule){
|
||||
DCapsule capsuleView = (DCapsule)geom;
|
||||
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
|
||||
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitcapsule.glb")) != null){
|
||||
//set color based on collision status, type, etc
|
||||
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
Vector3d position = PhysicsUtils.odeVecToJomlVec(capsuleView.getPosition());
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
//since you're directly accessing the quat from the body, need to adjust it to be in the correct orientation
|
||||
modelTransformMatrix.rotate(PhysicsUtils.odeQuatToJomlQuat(capsuleView.getQuaternion()).mul(new Quaterniond(0.707,0,0,0.707)));
|
||||
//the ode4j capsule's end caps are always at least radius length, the length only controls the distance between the two caps.
|
||||
//unfortunately that won't be easy to replicate with rendering tech currently; instead, run logic below
|
||||
double radius = capsuleView.getRadius();
|
||||
double length = capsuleView.getLength();
|
||||
if(length < radius) length = radius;
|
||||
modelTransformMatrix.scale(radius,length,radius);
|
||||
hitboxModel.setModelMatrix(modelTransformMatrix);
|
||||
hitboxModel.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//update pipeline state to use mats again
|
||||
renderPipelineState.setUseMaterial(true);
|
||||
|
||||
if(Globals.gameConfigCurrent.getSettings().graphicsDebugDrawNavmesh()){
|
||||
throw new Error("Not yet implemented!");
|
||||
}
|
||||
|
||||
debugBonesPipeline.render(openGLState, renderPipelineState);
|
||||
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color texture to use to draw a hitbox
|
||||
* @param shapeStatus The hitbox status
|
||||
* @param data The hitbox data
|
||||
* @return The texture path to use
|
||||
* Renders an area select
|
||||
* @param openGLState The opengl state
|
||||
* @param renderPipelineState The render pipeline state
|
||||
* @param modelTransformMatrix The model transform matrix
|
||||
* @param areaSelection The area selection
|
||||
*/
|
||||
private String getHitboxColor(HitboxState shapeStatus, HitboxData data){
|
||||
switch(data.getType()){
|
||||
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
|
||||
if(shapeStatus.getHadCollision()){
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
static void renderAreaSelection(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, AreaSelection areaSelection, String texturePath){
|
||||
Model model = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE);
|
||||
if(model != null){
|
||||
Texture texture = Globals.assetManager.fetchTexture(texturePath);
|
||||
if(texture != null){
|
||||
texture.bind(openGLState);
|
||||
}
|
||||
if(shapeStatus.isActive()){
|
||||
return "Textures/transparent_blue.png";
|
||||
Vector3d dims = new Vector3d(areaSelection.getRectEnd()).sub(areaSelection.getRectStart());
|
||||
Vector3d position = new Vector3d(areaSelection.getRectStart()).add(dims.x/2.0,dims.y/2.0,dims.z/2.0);
|
||||
//calculate camera-modified vector3d
|
||||
Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
|
||||
modelTransformMatrix.identity();
|
||||
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||
modelTransformMatrix.scale(dims);
|
||||
model.setModelMatrix(modelTransformMatrix);
|
||||
model.draw(renderPipelineState,openGLState);
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
case HitboxData.HITBOX_TYPE_HIT:
|
||||
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
|
||||
if(shapeStatus.getHadCollision()){
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
}
|
||||
if(shapeStatus.isActive()){
|
||||
if(shapeStatus.isBlockOverride()){
|
||||
return "Textures/transparent_blue.png";
|
||||
}
|
||||
return "Textures/transparent_red.png";
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
case HitboxData.HITBOX_TYPE_HURT:
|
||||
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
|
||||
if(shapeStatus.getHadCollision()){
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user