room detection within structures
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-16 16:37:05 -04:00
parent d656d75535
commit 2fc984c3f1
7 changed files with 449 additions and 158 deletions

View File

@ -1849,6 +1849,7 @@ Fix caching with deleted source files
Proof of concept of ui button calling engine code Proof of concept of ui button calling engine code
Script engine direct access to joml vectors Script engine direct access to joml vectors
Script engine passing objects back into methods successfully Script engine passing objects back into methods successfully
Room detection within structures

View File

@ -5,6 +5,7 @@ import java.util.ArrayList;
import org.joml.Vector3f; import org.joml.Vector3f;
import electrosphere.client.block.ClientBlockManager; import electrosphere.client.block.ClientBlockManager;
import electrosphere.client.block.StructureData;
import electrosphere.client.block.cells.ClientBlockCellManager; import electrosphere.client.block.cells.ClientBlockCellManager;
import electrosphere.client.chemistry.ClientChemistryCollisionCallback; import electrosphere.client.chemistry.ClientChemistryCollisionCallback;
import electrosphere.client.entity.character.ClientCharacterManager; import electrosphere.client.entity.character.ClientCharacterManager;
@ -187,6 +188,11 @@ public class ClientState {
*/ */
public int openInventoriesCount = 0; public int openInventoriesCount = 0;
/**
* The currently selected structure's data
*/
public StructureData currentStructureData;
/** /**
* Constructor * Constructor
*/ */

View File

@ -1,14 +1,19 @@
package electrosphere.client.block; package electrosphere.client.block;
import java.io.File; import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.client.interact.select.AreaSelection; import electrosphere.client.interact.select.AreaSelection;
import electrosphere.client.interact.select.AreaSelection.AreaSelectionType;
import electrosphere.client.scene.ClientWorldData; import electrosphere.client.scene.ClientWorldData;
import electrosphere.data.block.BlockFab; import electrosphere.data.block.BlockFab;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.util.math.HashUtils;
/** /**
* Class for selecting blocks on the client * Class for selecting blocks on the client
@ -128,4 +133,100 @@ public class ClientBlockSelection {
return fab; 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;
}
} }

View 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;
}
}

View File

@ -1,6 +1,7 @@
package electrosphere.client.interact.select; package electrosphere.client.interact.select;
import org.graalvm.polyglot.HostAccess.Export; import org.graalvm.polyglot.HostAccess.Export;
import org.joml.AABBd;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -42,6 +43,11 @@ public class AreaSelection {
*/ */
private Vector3d rectEnd; private Vector3d rectEnd;
/**
* The AABB of the area selection
*/
private AABBd aabb;
/** /**
* Creates a rectangular selection * Creates a rectangular selection
* @param start The start point * @param start The start point
@ -62,6 +68,7 @@ public class AreaSelection {
rVal.type = AreaSelectionType.RECTANGULAR; rVal.type = AreaSelectionType.RECTANGULAR;
rVal.rectStart = start; rVal.rectStart = start;
rVal.rectEnd = end; rVal.rectEnd = end;
rVal.aabb = new AABBd(start, end);
return rVal; return rVal;
} }
@ -369,4 +376,13 @@ public class AreaSelection {
return rectEnd; 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);
}
} }

View File

@ -5,6 +5,7 @@ import java.io.File;
import org.joml.Vector3d; import org.joml.Vector3d;
import electrosphere.client.block.ClientBlockSelection; import electrosphere.client.block.ClientBlockSelection;
import electrosphere.client.block.StructureData;
import electrosphere.client.interact.select.AreaSelection; import electrosphere.client.interact.select.AreaSelection;
import electrosphere.data.block.BlockFab; import electrosphere.data.block.BlockFab;
import electrosphere.data.block.BlockFabMetadata; import electrosphere.data.block.BlockFabMetadata;
@ -33,6 +34,14 @@ public class ImGuiStructureTab {
} }
} else { } else {
BlockFab currentFab = Globals.clientState.clientLevelEditorData.getCurrentFab(); 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")){ if(ImGui.button("Convert current selection to room")){
AreaSelection currentSelection = Globals.cursorState.getAreaSelection(); AreaSelection currentSelection = Globals.cursorState.getAreaSelection();
if(currentSelection != null){ if(currentSelection != null){

View File

@ -13,6 +13,7 @@ import org.ode4j.ode.DSphere;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.interact.select.AreaSelection;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsUtils; import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
@ -76,181 +77,43 @@ public class DebugContentPipeline implements RenderPipeline {
Matrix4d modelTransformMatrix = new Matrix4d(); Matrix4d modelTransformMatrix = new Matrix4d();
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawCollisionSpheresClient()){ if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawCollisionSpheresClient()){
Model hitboxModel;
for(HitboxCollectionState hitboxState : Globals.clientState.clientSceneWrapper.getHitboxManager().getAllHitboxes()){ for(HitboxCollectionState hitboxState : Globals.clientState.clientSceneWrapper.getHitboxManager().getAllHitboxes()){
for(DGeom geom : hitboxState.getGeometries()){ DebugContentPipeline.renderHitboxes(openGLState, renderPipelineState, modelTransformMatrix, hitboxState);
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);
}
}
}
} }
} }
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawCollisionSpheresServer()){ if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawCollisionSpheresServer()){
Model hitboxModel;
int serverIdForClientEntity = Globals.clientState.clientSceneWrapper.mapClientToServerId(Globals.clientState.playerEntity.getId()); int serverIdForClientEntity = Globals.clientState.clientSceneWrapper.mapClientToServerId(Globals.clientState.playerEntity.getId());
Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity); Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
Realm playerRealm = Globals.serverState.realmManager.getEntityRealm(serverPlayerEntity); Realm playerRealm = Globals.serverState.realmManager.getEntityRealm(serverPlayerEntity);
List<HitboxCollectionState> hitboxStates = new LinkedList<HitboxCollectionState>(playerRealm.getHitboxManager().getAllHitboxes()); List<HitboxCollectionState> hitboxStates = new LinkedList<HitboxCollectionState>(playerRealm.getHitboxManager().getAllHitboxes());
for(HitboxCollectionState hitboxState : hitboxStates){ for(HitboxCollectionState hitboxState : hitboxStates){
for(DGeom geom : hitboxState.getGeometries()){ DebugContentPipeline.renderHitboxes(openGLState, renderPipelineState, modelTransformMatrix, hitboxState);
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);
}
}
}
} }
} }
if(Globals.gameConfigCurrent.getSettings().graphicsDebugDrawPhysicsObjects()){ if(Globals.gameConfigCurrent.getSettings().graphicsDebugDrawPhysicsObjects()){
Model physicsGraphicsModel;
CollisionEngine engine = Globals.clientState.clientSceneWrapper.getCollisionEngine(); CollisionEngine engine = Globals.clientState.clientSceneWrapper.getCollisionEngine();
for(Collidable collidable : engine.getCollidables()){ for(Collidable collidable : engine.getCollidables()){
Entity physicsEntity = collidable.getParent(); Entity physicsEntity = collidable.getParent();
if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE) != null){ if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE) != null){
CollidableTemplate template = (CollidableTemplate)physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE); CollidableTemplate template = (CollidableTemplate)physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
switch(template.getType()){ DebugContentPipeline.renderCollidable(openGLState, renderPipelineState, modelTransformMatrix, physicsEntity, template);
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: { }
if((physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER)) != null){ }
//set color based on collision status, type, etc }
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
if(texture != null){ if(Globals.clientState.currentStructureData != null){
texture.bind(openGLState); if(Globals.clientState.currentStructureData.getBoundingArea() != null){
} DebugContentPipeline.renderAreaSelection(
Vector3d position = EntityUtils.getPosition(physicsEntity); openGLState, renderPipelineState, modelTransformMatrix,
//calculate camera-modified vector3d Globals.clientState.currentStructureData.getBoundingArea(), AssetDataStrings.TEXTURE_RED_TRANSPARENT
Vector3d cameraModifiedPosition = new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera)); );
modelTransformMatrix.identity(); if(Globals.clientState.currentStructureData.getRooms() != null){
modelTransformMatrix.translate(cameraModifiedPosition); for(AreaSelection roomArea : Globals.clientState.currentStructureData.getRooms()){
modelTransformMatrix.rotate(EntityUtils.getRotation(physicsEntity)); DebugContentPipeline.renderAreaSelection(
modelTransformMatrix.scale(template.getDimension1(),template.getDimension2() * 0.5,template.getDimension3()); openGLState, renderPipelineState, modelTransformMatrix,
physicsGraphicsModel.setModelMatrix(modelTransformMatrix); roomArea, AssetDataStrings.TEXTURE_TEAL_TRANSPARENT
physicsGraphicsModel.draw(renderPipelineState,openGLState); );
}
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
if((physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE)) != null){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
if(texture != null){
texture.bind(openGLState);
}
Vector3d position = EntityUtils.getPosition(physicsEntity);
Quaterniond rotation = EntityUtils.getRotation(physicsEntity);
//calculate camera-modified vector3d
Vector3d cameraModifiedPosition = new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(rotation);
modelTransformMatrix.scale(template.getDimension1(),template.getDimension2(),template.getDimension3());
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
physicsGraphicsModel.draw(renderPipelineState,openGLState);
}
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
if((physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCAPSULE)) != null){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
if(texture != null){
texture.bind(openGLState);
}
Vector3d position = EntityUtils.getPosition(physicsEntity);
Quaterniond rotation = EntityUtils.getRotation(physicsEntity);
//calculate camera-modified vector3d
Vector3d cameraModifiedPosition = new Vector3d(position).add(template.getOffsetX(),template.getDimension1() + template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(rotation);
modelTransformMatrix.scale(template.getDimension1(),template.getDimension2() * 0.5 + template.getDimension1() + template.getDimension1(),template.getDimension3());
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
physicsGraphicsModel.draw(renderPipelineState,openGLState);
}
} break;
default: {
throw new Error("Unsupported shape type!");
}
} }
} }
} }
@ -306,7 +169,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param data The hitbox data * @param data The hitbox data
* @return The texture path to use * @return The texture path to use
*/ */
private String getHitboxColor(HitboxState shapeStatus, HitboxData data){ private static String getHitboxColor(HitboxState shapeStatus, HitboxData data){
switch(data.getType()){ switch(data.getType()){
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: { case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
if(shapeStatus.getHadCollision()){ if(shapeStatus.getHadCollision()){
@ -341,6 +204,165 @@ public class DebugContentPipeline implements RenderPipeline {
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){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
if(texture != null){
texture.bind(openGLState);
}
Vector3d position = EntityUtils.getPosition(physicsEntity);
//calculate camera-modified vector3d
Vector3d cameraModifiedPosition = new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(EntityUtils.getRotation(physicsEntity));
modelTransformMatrix.scale(template.getDimension1(),template.getDimension2() * 0.5,template.getDimension3());
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
physicsGraphicsModel.draw(renderPipelineState,openGLState);
}
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
if((physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE)) != null){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
if(texture != null){
texture.bind(openGLState);
}
Vector3d position = EntityUtils.getPosition(physicsEntity);
Quaterniond rotation = EntityUtils.getRotation(physicsEntity);
//calculate camera-modified vector3d
Vector3d cameraModifiedPosition = new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(rotation);
modelTransformMatrix.scale(template.getDimension1(),template.getDimension2(),template.getDimension3());
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
physicsGraphicsModel.draw(renderPipelineState,openGLState);
}
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
if((physicsGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCAPSULE)) != null){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture("Textures/transparent_blue.png");
if(texture != null){
texture.bind(openGLState);
}
Vector3d position = EntityUtils.getPosition(physicsEntity);
Quaterniond rotation = EntityUtils.getRotation(physicsEntity);
//calculate camera-modified vector3d
Vector3d cameraModifiedPosition = new Vector3d(position).add(template.getOffsetX(),template.getDimension1() + template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(rotation);
modelTransformMatrix.scale(template.getDimension1(),template.getDimension2() * 0.5 + template.getDimension1() + template.getDimension1(),template.getDimension3());
physicsGraphicsModel.setModelMatrix(modelTransformMatrix);
physicsGraphicsModel.draw(renderPipelineState,openGLState);
}
} break;
default: {
throw new Error("Unsupported shape type!");
}
}
}
}
/**
* 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 = 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);
}
}
}
}
/**
* 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
*/
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);
}
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);
}
}
/** /**
* Gets the bone debugging pipeline * Gets the bone debugging pipeline
* @return The bone debugging pipeline * @return The bone debugging pipeline