Renderer/src/main/java/electrosphere/client/fluid/cells/FluidCell.java
austin 58d1d86262
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
More stuff
2024-03-20 22:00:40 -04:00

297 lines
13 KiB
Java

package electrosphere.client.fluid.cells;
import org.joml.Vector3d;
import org.joml.Vector3i;
import org.ode4j.ode.DBody;
import electrosphere.client.fluid.cache.FluidChunkData;
import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.fluid.FluidChunk;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.renderer.texture.Texture;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
*
* @author satellite
*/
public class FluidCell {
//the position of the draw cell in world coordinates
Vector3i worldPos;
FluidChunkData data;
Entity modelEntity;
ShaderProgram program;
DBody physicsObject;
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
//the value of an empty fluid cell weight that is not neighbored by a fluid value
public static final float ISO_SURFACE_EMPTY = -1;
FluidCell(){
}
/**
* Constructs a drawcell object
*/
public static FluidCell generateFluidCell(
Vector3i worldPos,
FluidChunkData data,
ShaderProgram program
){
FluidCell rVal = new FluidCell();
rVal.worldPos = worldPos;
rVal.program = program;
rVal.data = data;
return rVal;
}
/**
* Generates a drawable entity based on this chunk
*/
public void generateDrawableEntity(){
if(modelEntity != null){
Globals.clientScene.deregisterEntity(modelEntity);
}
fillInData();
modelEntity = FluidChunk.clientCreateFluidChunkEntity(weights);
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
}
protected Vector3d getRealPos(){
return new Vector3d(
worldPos.x * FluidChunkData.CHUNK_SIZE,
worldPos.y * FluidChunkData.CHUNK_SIZE,
worldPos.z * FluidChunkData.CHUNK_SIZE
);
}
/**
* Destroys a drawcell including its physics
*/
public void destroy(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
EntityUtils.cleanUpEntity(modelEntity);
//destruct model
String modelPath = (String)modelEntity.getData(EntityDataStrings.DATA_STRING_MODEL_PATH);
Globals.assetManager.deregisterModelPath(modelPath);
}
/**
* Gets the current chunk data for this draw cell
* @return The chunk data
*/
public FluidChunkData getData(){
return data;
}
/**
* Fills in the internal arrays of data for generate terrain models
*/
private void fillInData(){
//
//fill in data
//
//main chunk
FluidChunkData currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos);
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
weights[x][y][z] = currentChunk.getWeight(x,y,z);
}
}
}
//face X
if(worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y, worldPos.z);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = currentChunk.getWeight(0, i, j);
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = ISO_SURFACE_EMPTY;
}
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = ISO_SURFACE_EMPTY;
}
}
}
//face Y
if(worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y + 1, worldPos.z);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = currentChunk.getWeight(i, 0, j);
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = ISO_SURFACE_EMPTY;
}
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = ISO_SURFACE_EMPTY;
}
}
}
//face Z
if(worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z + 1);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, j, 0);
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
}
}
//edge X-Y
if(
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize()
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = currentChunk.getWeight(0, 0, i);
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = ISO_SURFACE_EMPTY;
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = ISO_SURFACE_EMPTY;
}
}
//edge X-Z
if(
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y, worldPos.z + 1);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, i, 0);
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
}
//edge Y-Z
if(
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y + 1, worldPos.z + 1);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, 0, 0);
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
}
if(
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z + 1);
if(currentChunk != null){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, 0, 0);
} else {
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
} else {
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
}
//now set neighboring air weights based on nearby fluid count
//idea being that we dont have the snapping behavior from iso surface jumping from -1->0.01
int[] neighborIndexX = new int[]{-1,1,0,0,0,0};
int[] neighborIndexY = new int[]{0,0,-1,1,0,0};
int[] neighborIndexZ = new int[]{0,0,0,0,-1,1};
for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){
if(weights[x][y][z] > 0){
continue;
}
for(int i = 0; i < 6; i++){
int currX = x + neighborIndexX[i];
int currY = y + neighborIndexY[i];
int currZ = z + neighborIndexZ[i];
if(
currX >= 0 && currX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE &&
currY >= 0 && currY < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE &&
currZ >= 0 && currZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE &&
(1 + weights[x][y][z]) < weights[currX][currY][currZ]
){
weights[x][y][z] = -(1 - weights[currX][currY][currZ]);
if(weights[x][y][z] >= 0){
weights[x][y][z] = -0.01f;
}
}
}
}
}
}
}
}