297 lines
13 KiB
Java
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|