Fluid simulation scaffolding
This commit is contained in:
parent
7d4b3b1a97
commit
e225cac5cf
208
assets/Shaders/fluid1/fluid1.fs
Normal file
208
assets/Shaders/fluid1/fluid1.fs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
#define NR_POINT_LIGHTS 10
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
|
||||||
|
layout (std140) uniform Lights {
|
||||||
|
// this is how many because we have to align
|
||||||
|
// bytes it SHOULD in multiples of 16, this
|
||||||
|
// take it where it ACTUALLY is
|
||||||
|
//
|
||||||
|
//refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
|
||||||
|
//
|
||||||
|
// base alignment aligned offset
|
||||||
|
//direct light
|
||||||
|
vec3 dLDirection; // 16 0
|
||||||
|
vec3 dLAmbient; // 16 16
|
||||||
|
vec3 dLDiffuse; // 16 32
|
||||||
|
vec3 dLSpecular; // 16 48
|
||||||
|
|
||||||
|
//point light
|
||||||
|
vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64
|
||||||
|
float pLconstant[NR_POINT_LIGHTS]; // 16*10 224
|
||||||
|
float pLlinear[NR_POINT_LIGHTS]; // 16*10 384
|
||||||
|
float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544
|
||||||
|
vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704
|
||||||
|
vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864
|
||||||
|
vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024
|
||||||
|
|
||||||
|
//for a total size of 1184
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
sampler2D diffuse;
|
||||||
|
sampler2D specular;
|
||||||
|
float shininess;
|
||||||
|
};
|
||||||
|
|
||||||
|
in vec3 FragPos;
|
||||||
|
in vec3 Normal;
|
||||||
|
in vec2 texPlane1;
|
||||||
|
in vec2 texPlane2;
|
||||||
|
in vec2 texPlane3;
|
||||||
|
in vec4 FragPosLightSpace;
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec3 viewPos;
|
||||||
|
// uniform DirLight dirLight;
|
||||||
|
// uniform PointLight pointLights[NR_POINT_LIGHTS];
|
||||||
|
// uniform SpotLight spotLight;
|
||||||
|
uniform Material material;
|
||||||
|
|
||||||
|
//texture stuff
|
||||||
|
// uniform sampler2D ourTexture;
|
||||||
|
uniform int hasTransparency;
|
||||||
|
// uniform sampler2D specularTexture;
|
||||||
|
|
||||||
|
//light depth map
|
||||||
|
uniform sampler2D shadowMap;
|
||||||
|
|
||||||
|
|
||||||
|
// function prototypes
|
||||||
|
// vec3 CalcDirLight(vec3 normal, vec3 viewDir);
|
||||||
|
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||||
|
// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||||
|
float calcLightIntensityTotal(vec3 normal);
|
||||||
|
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
|
||||||
|
vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, Material material);
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec3 norm = normalize(Normal);
|
||||||
|
vec3 viewDir = normalize(viewPos - FragPos);
|
||||||
|
|
||||||
|
//grab light intensity
|
||||||
|
float lightIntensity = calcLightIntensityTotal(norm);
|
||||||
|
|
||||||
|
//get color of base texture
|
||||||
|
vec3 textureColor = getColor(texPlane1, texPlane2, texPlane3, norm, material);
|
||||||
|
|
||||||
|
//shadow
|
||||||
|
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
|
||||||
|
|
||||||
|
//calculate final color
|
||||||
|
vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4);
|
||||||
|
// vec3 lightAmount = CalcDirLight(norm, viewDir);
|
||||||
|
// for(int i = 0; i < NR_POINT_LIGHTS; i++){
|
||||||
|
// lightAmount += CalcPointLight(i, norm, FragPos, viewDir);
|
||||||
|
// }
|
||||||
|
|
||||||
|
//this final calculation is for transparency
|
||||||
|
FragColor = vec4(finalColor, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, Material material){
|
||||||
|
|
||||||
|
vec3 weights = abs(normal);
|
||||||
|
|
||||||
|
vec3 albedoX = texture(material.diffuse, texPlane1).rgb;
|
||||||
|
vec3 albedoY = texture(material.diffuse, texPlane2).rgb;
|
||||||
|
vec3 albedoZ = texture(material.diffuse, texPlane3).rgb;
|
||||||
|
|
||||||
|
|
||||||
|
return (albedoX * weights.x + albedoY * weights.y + albedoZ * weights.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float calcLightIntensityAmbient(){
|
||||||
|
//calculate average of ambient light
|
||||||
|
float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
|
||||||
|
return avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float calcLightIntensityDir(vec3 normal){
|
||||||
|
vec3 lightDir = normalize(-dLDirection);
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float calcLightIntensityTotal(vec3 normal){
|
||||||
|
//ambient intensity
|
||||||
|
float ambientLightIntensity = calcLightIntensityAmbient();
|
||||||
|
|
||||||
|
//get direct intensity
|
||||||
|
float directLightIntensity = calcLightIntensityDir(normal);
|
||||||
|
|
||||||
|
//sum
|
||||||
|
float total = ambientLightIntensity + directLightIntensity;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
vec3 getTotalLightColor(vec3 normal){
|
||||||
|
//get the direct light color adjusted for intensity
|
||||||
|
vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal);
|
||||||
|
|
||||||
|
//sum light colors
|
||||||
|
vec3 totalLightColor = diffuseLightColor;
|
||||||
|
return totalLightColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
|
||||||
|
vec3 lightDir = normalize(pLposition[i] - fragPos);
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
// specular shading
|
||||||
|
// vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
|
// attenuation
|
||||||
|
float distance = length(pLposition[i] - fragPos);
|
||||||
|
float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
|
||||||
|
// combine results
|
||||||
|
vec3 ambient = pLambient[i];
|
||||||
|
vec3 diffuse = pLdiffuse[i] * diff;
|
||||||
|
ambient *= attenuation;
|
||||||
|
diffuse *= attenuation;
|
||||||
|
// specular *= attenuation;
|
||||||
|
vec3 specular = vec3(0,0,0);
|
||||||
|
|
||||||
|
vec3 finalValue = (ambient + diffuse + specular);
|
||||||
|
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
|
||||||
|
|
||||||
|
return finalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){
|
||||||
|
|
||||||
|
// perform perspective divide
|
||||||
|
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
|
|
||||||
|
//transform to NDC
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
|
//get closest depth from light's POV
|
||||||
|
float closestDepth = texture(shadowMap, projCoords.xy).r;
|
||||||
|
|
||||||
|
//get depth of current fragment
|
||||||
|
float currentDepth = projCoords.z;
|
||||||
|
|
||||||
|
//calculate bias
|
||||||
|
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||||
|
|
||||||
|
//calculate shadow value
|
||||||
|
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
|
||||||
|
|
||||||
|
if(projCoords.z > 1.0){
|
||||||
|
shadow = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate dot product, if it is >0 we know they're parallel-ish therefore should disregard the shadow mapping
|
||||||
|
//ie the fragment is already facing away from the light source
|
||||||
|
float dotprod = dot(normalize(lightDir),normalize(normal));
|
||||||
|
|
||||||
|
if(dotprod > 0.0){
|
||||||
|
shadow = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shadow = currentDepth;
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
62
assets/Shaders/fluid1/fluid1.vs
Normal file
62
assets/Shaders/fluid1/fluid1.vs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//Vertex Shader
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
//defines
|
||||||
|
#define TEXTURE_MAP_SCALE 3.0
|
||||||
|
|
||||||
|
|
||||||
|
//input buffers
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec3 aNormal;
|
||||||
|
layout (location = 4) in vec2 aTex;
|
||||||
|
|
||||||
|
|
||||||
|
//coordinate space transformation matrices
|
||||||
|
uniform mat4 transform;
|
||||||
|
uniform mat4 model;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 projection;
|
||||||
|
uniform mat4 lightSpaceMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//output buffers
|
||||||
|
out vec3 Normal;
|
||||||
|
out vec3 FragPos;
|
||||||
|
out vec2 texPlane1;
|
||||||
|
out vec2 texPlane2;
|
||||||
|
out vec2 texPlane3;
|
||||||
|
out vec4 FragPosLightSpace;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//normalize posiiton and normal
|
||||||
|
vec4 FinalVertex = vec4(aPos, 1.0);
|
||||||
|
vec4 FinalNormal = vec4(aNormal, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
//push frag, normal, and texture positions to fragment shader
|
||||||
|
FragPos = vec3(model * FinalVertex);
|
||||||
|
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||||
|
|
||||||
|
//reference https://catlikecoding.com/unity/tutorials/advanced-rendering/triplanar-mapping/
|
||||||
|
texPlane1 = aPos.zy * TEXTURE_MAP_SCALE;
|
||||||
|
texPlane2 = aPos.xz * TEXTURE_MAP_SCALE;
|
||||||
|
texPlane3 = aPos.xy * TEXTURE_MAP_SCALE;
|
||||||
|
|
||||||
|
//flip first coordinate if the normal is negative
|
||||||
|
//this minimizes texture flipping
|
||||||
|
texPlane1.x = texPlane1.x * sign(Normal.x);
|
||||||
|
texPlane2.x = texPlane2.x * sign(Normal.y);
|
||||||
|
texPlane3.x = texPlane3.x * sign(Normal.z);
|
||||||
|
|
||||||
|
|
||||||
|
//shadow map stuff
|
||||||
|
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
//set final position with opengl space
|
||||||
|
gl_Position = projection * view * model * FinalVertex;
|
||||||
|
}
|
||||||
82
src/main/java/electrosphere/client/fluid/cache/ClientFluidCache.java
vendored
Normal file
82
src/main/java/electrosphere/client/fluid/cache/ClientFluidCache.java
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package electrosphere.client.fluid.cache;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acts as a cache in front of fluid model to streamline receiving chunks
|
||||||
|
*/
|
||||||
|
public class ClientFluidCache {
|
||||||
|
|
||||||
|
//cache capacity
|
||||||
|
int cacheSize;
|
||||||
|
//the map of chunk key -> chunk data
|
||||||
|
Map<String,FluidChunkData> cacheMap = new ConcurrentHashMap<String,FluidChunkData>();
|
||||||
|
//the list of keys in the cache
|
||||||
|
List<String> cacheList = new CopyOnWriteArrayList<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param cacheSize The capacity of the cache
|
||||||
|
*/
|
||||||
|
public ClientFluidCache(int cacheSize){
|
||||||
|
this.cacheSize = cacheSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a chunk data to the fluid cache
|
||||||
|
* @param worldX The x world position
|
||||||
|
* @param worldY The y world position
|
||||||
|
* @param worldZ The z world position
|
||||||
|
* @param chunkData The chunk data to add at the specified positions
|
||||||
|
*/
|
||||||
|
public void addChunkDataToCache(int worldX, int worldY, int worldZ, FluidChunkData chunkData){
|
||||||
|
cacheMap.put(getKey(worldX,worldY,worldZ),chunkData);
|
||||||
|
while(cacheList.size() > cacheSize){
|
||||||
|
String currentChunk = cacheList.remove(0);
|
||||||
|
cacheMap.remove(currentChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a key for the cache based on the position provided
|
||||||
|
* @param worldX The x world position
|
||||||
|
* @param worldY The y world position
|
||||||
|
* @param worldZ The z world position
|
||||||
|
* @return The cache key
|
||||||
|
*/
|
||||||
|
public String getKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the cache contains chunk data at a given world point
|
||||||
|
* @param worldX The x world position
|
||||||
|
* @param worldY The y world position
|
||||||
|
* @param worldZ The z world position
|
||||||
|
* @return True if the cache contains chunk data at the specified point, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
||||||
|
return cacheMap.containsKey(getKey(worldX,worldY,worldZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets chunk data at the given world point
|
||||||
|
* @param worldX The x world position
|
||||||
|
* @param worldY The y world position
|
||||||
|
* @param worldZ The z world position
|
||||||
|
* @return The chunk data if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public FluidChunkData getSubChunkDataAtPoint(int worldX, int worldY, int worldZ){
|
||||||
|
return cacheMap.get(getKey(worldX,worldY,worldZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
160
src/main/java/electrosphere/client/fluid/cache/FluidChunkData.java
vendored
Normal file
160
src/main/java/electrosphere/client/fluid/cache/FluidChunkData.java
vendored
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package electrosphere.client.fluid.cache;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A container of data about a chunk of fluid
|
||||||
|
*/
|
||||||
|
public class FluidChunkData {
|
||||||
|
|
||||||
|
//The size of a chunk in virtual data
|
||||||
|
public static final int CHUNK_SIZE = ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
//The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk
|
||||||
|
public static final int CHUNK_DATA_GENERATOR_SIZE = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE;
|
||||||
|
|
||||||
|
//What type of fluid is in this voxel, eg stone vs dirt vs grass, etc
|
||||||
|
int[][][] voxelType;
|
||||||
|
//How much of that fluid type is in this voxel
|
||||||
|
float[][][] voxelWeight;
|
||||||
|
|
||||||
|
//the list of positions modified since the last call to resetModifiedPositions
|
||||||
|
//Used in DrawCell to keep track of which positions to invalidate
|
||||||
|
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the voxel type array in this container
|
||||||
|
* @return The voxel type array
|
||||||
|
*/
|
||||||
|
public int[][][] getVoxelType(){
|
||||||
|
return voxelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the voxel type array in this container
|
||||||
|
* @param voxelType The voxel type array
|
||||||
|
*/
|
||||||
|
public void setVoxelType(int[][][] voxelType){
|
||||||
|
//mark changed cells
|
||||||
|
if(this.voxelType != null){
|
||||||
|
for(int x = 0; x < CHUNK_SIZE; x++){
|
||||||
|
for(int y = 0; y < CHUNK_SIZE; y++){
|
||||||
|
for(int z = 0; z < CHUNK_SIZE; z++){
|
||||||
|
if(voxelType[x][y][z] != this.voxelType[x][y][z]){
|
||||||
|
String key = getVoxelPositionKey(new Vector3i(x,y,z));
|
||||||
|
if(!modifiedSinceLastGeneration.contains(key)){
|
||||||
|
modifiedSinceLastGeneration.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update data
|
||||||
|
this.voxelType = voxelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the voxel weight array in this container
|
||||||
|
* @return The voxel weight array
|
||||||
|
*/
|
||||||
|
public float[][][] getVoxelWeight(){
|
||||||
|
return voxelWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the voxel weight array in this container
|
||||||
|
* @param voxelWeight The voxel weight array
|
||||||
|
*/
|
||||||
|
public void setVoxelWeight(float[][][] voxelWeight){
|
||||||
|
//mark changed cells
|
||||||
|
if(this.voxelWeight != null){
|
||||||
|
for(int x = 0; x < CHUNK_SIZE; x++){
|
||||||
|
for(int y = 0; y < CHUNK_SIZE; y++){
|
||||||
|
for(int z = 0; z < CHUNK_SIZE; z++){
|
||||||
|
if(voxelWeight[x][y][z] != this.voxelWeight[x][y][z]){
|
||||||
|
String key = getVoxelPositionKey(new Vector3i(x,y,z));
|
||||||
|
if(!modifiedSinceLastGeneration.contains(key)){
|
||||||
|
modifiedSinceLastGeneration.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update data
|
||||||
|
this.voxelWeight = voxelWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the value of a single voxel in the chunk
|
||||||
|
* @param localX The local position X
|
||||||
|
* @param localY The local position Y
|
||||||
|
* @param localZ The local position Z
|
||||||
|
* @param weight The weight to set it to
|
||||||
|
* @param type The type to set the voxel to
|
||||||
|
*/
|
||||||
|
public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
||||||
|
voxelWeight[localX][localY][localZ] = weight;
|
||||||
|
voxelType[localX][localY][localZ] = type;
|
||||||
|
//store as modified in cache
|
||||||
|
String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ));
|
||||||
|
if(!modifiedSinceLastGeneration.contains(key)){
|
||||||
|
modifiedSinceLastGeneration.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the weight of a voxel at a poisiton
|
||||||
|
* @param localPosition The local position
|
||||||
|
* @return The weight of the specified voxel
|
||||||
|
*/
|
||||||
|
public float getWeight(Vector3i localPosition){
|
||||||
|
return voxelWeight[localPosition.x][localPosition.y][localPosition.z];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of a voxel at a position
|
||||||
|
* @param localPosition The local position
|
||||||
|
* @return The type of the specified voxel
|
||||||
|
*/
|
||||||
|
public int getType(Vector3i localPosition){
|
||||||
|
return voxelType[localPosition.x][localPosition.y][localPosition.z];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the cache of modified positions
|
||||||
|
*/
|
||||||
|
public void resetModifiedPositions(){
|
||||||
|
this.modifiedSinceLastGeneration.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of all modified positions since the last call to resetModifiedPositions
|
||||||
|
* @return The set of all modified positions
|
||||||
|
*/
|
||||||
|
public Set<Vector3i> getModifiedPositions(){
|
||||||
|
Set<Vector3i> rVal = new HashSet<Vector3i>();
|
||||||
|
for(String key : modifiedSinceLastGeneration){
|
||||||
|
String[] split = key.split("_");
|
||||||
|
rVal.add(new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2])));
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a key for the modifiedSinceLastGeneration set based on a voxel position
|
||||||
|
* @param position The voxel position
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
private String getVoxelPositionKey(Vector3i position){
|
||||||
|
return position.x + "_" + position.y + "_" + position.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,414 @@
|
|||||||
|
package electrosphere.client.fluid.cells;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
|
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||||
|
import electrosphere.renderer.ShaderProgram;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author satellite
|
||||||
|
*/
|
||||||
|
public class DrawCellManager {
|
||||||
|
|
||||||
|
|
||||||
|
//the center of this cell manager's array in cell space
|
||||||
|
int cellX;
|
||||||
|
int cellY;
|
||||||
|
int cellZ;
|
||||||
|
|
||||||
|
|
||||||
|
//the dimensions of the world that this cell manager can handles
|
||||||
|
int cellWidth;
|
||||||
|
|
||||||
|
//the width of a minicell in this manager
|
||||||
|
int miniCellWidth;
|
||||||
|
|
||||||
|
//all currently displaying mini cells
|
||||||
|
Set<FluidDrawCell> cells;
|
||||||
|
Map<String,FluidDrawCell> keyCellMap = new HashMap<String,FluidDrawCell>();
|
||||||
|
Set<String> hasNotRequested;
|
||||||
|
Set<String> hasRequested;
|
||||||
|
Set<String> drawable;
|
||||||
|
Set<String> undrawable;
|
||||||
|
Set<String> updateable;
|
||||||
|
|
||||||
|
|
||||||
|
ShaderProgram program;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// int drawRadius = 5;
|
||||||
|
int drawStepdownInterval = 3;
|
||||||
|
int drawStepdownValue = 25;
|
||||||
|
|
||||||
|
double drawRadius = 200;
|
||||||
|
|
||||||
|
int physicsRadius = 3;
|
||||||
|
|
||||||
|
int worldBoundDiscreteMin = 0;
|
||||||
|
int worldBoundDiscreteMax = 0;
|
||||||
|
|
||||||
|
//client terrain manager
|
||||||
|
// ClientTerrainManager clientTerrainManager;
|
||||||
|
|
||||||
|
|
||||||
|
//ready to start updating?
|
||||||
|
boolean update = false;
|
||||||
|
|
||||||
|
//controls whether we try to generate the drawable entities
|
||||||
|
//we want this to be false when in server-only mode
|
||||||
|
boolean generateDrawables = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DrawCellManager constructor
|
||||||
|
* @param commonWorldData The common world data
|
||||||
|
* @param clientTerrainManager The client terrain manager
|
||||||
|
* @param discreteX The initial discrete position X coordinate
|
||||||
|
* @param discreteY The initial discrete position Y coordinate
|
||||||
|
*/
|
||||||
|
public DrawCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
|
||||||
|
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
|
||||||
|
cells = new HashSet<FluidDrawCell>();
|
||||||
|
hasNotRequested = new HashSet<String>();
|
||||||
|
drawable = new HashSet<String>();
|
||||||
|
undrawable = new HashSet<String>();
|
||||||
|
updateable = new HashSet<String>();
|
||||||
|
hasRequested = new HashSet<String>();
|
||||||
|
|
||||||
|
cellX = discreteX;
|
||||||
|
cellY = discreteY;
|
||||||
|
cellZ = discreteZ;
|
||||||
|
|
||||||
|
program = Globals.terrainShaderProgram;
|
||||||
|
|
||||||
|
// drawRadius = Globals.userSettings.getGraphicsPerformanceLODChunkRadius();
|
||||||
|
drawStepdownInterval = Globals.userSettings.getGameplayPhysicsCellRadius();
|
||||||
|
physicsRadius = Globals.userSettings.getGameplayPhysicsCellRadius();
|
||||||
|
|
||||||
|
invalidateAllCells();
|
||||||
|
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawCellManager(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCell(Vector3i cellPos){
|
||||||
|
cellX = cellPos.x;
|
||||||
|
cellY = cellPos.y;
|
||||||
|
cellZ = cellPos.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateUnrequestedCell(){
|
||||||
|
if(hasNotRequested.size() > 0){
|
||||||
|
String targetKey = hasNotRequested.iterator().next();
|
||||||
|
hasNotRequested.remove(targetKey);
|
||||||
|
Vector3i worldPos = getVectorFromKey(targetKey);
|
||||||
|
// Vector3i vector = getVectorFromKey(targetKey);
|
||||||
|
// int currentCellX = cellX - drawRadius + vector.x;
|
||||||
|
// int currentCellY = cellY - drawRadius + vector.y;
|
||||||
|
// int currentCellZ = cellZ - drawRadius + vector.z;
|
||||||
|
|
||||||
|
if(
|
||||||
|
worldPos.x >= 0 &&
|
||||||
|
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.y >= 0 &&
|
||||||
|
worldPos.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.z >= 0 &&
|
||||||
|
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
// if(!hasRequested.contains(targetKey)){
|
||||||
|
//client should request chunk data from server
|
||||||
|
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage(
|
||||||
|
worldPos.x,
|
||||||
|
worldPos.y,
|
||||||
|
worldPos.z
|
||||||
|
));
|
||||||
|
undrawable.add(targetKey);
|
||||||
|
hasRequested.add(targetKey);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes one of the undrawable cells drawable
|
||||||
|
*/
|
||||||
|
void makeCellDrawable(){
|
||||||
|
|
||||||
|
if(undrawable.size() > 0){
|
||||||
|
String targetKey = undrawable.iterator().next();
|
||||||
|
Vector3i worldPos = getVectorFromKey(targetKey);
|
||||||
|
if(
|
||||||
|
worldPos.x >= 0 &&
|
||||||
|
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.y >= 0 &&
|
||||||
|
worldPos.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.z >= 0 &&
|
||||||
|
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
if(containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z)){
|
||||||
|
FluidDrawCell cell = FluidDrawCell.generateFluidCell(
|
||||||
|
worldPos,
|
||||||
|
Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z),
|
||||||
|
program
|
||||||
|
);
|
||||||
|
cells.add(cell);
|
||||||
|
keyCellMap.put(targetKey,cell);
|
||||||
|
// undrawable.add(targetKey);
|
||||||
|
undrawable.remove(targetKey);
|
||||||
|
drawable.add(targetKey);
|
||||||
|
//make drawable entity
|
||||||
|
keyCellMap.get(targetKey).generateDrawableEntity();
|
||||||
|
//evaluate for foliage
|
||||||
|
Globals.clientFoliageManager.evaluateChunk(worldPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a cell that can be updated
|
||||||
|
*/
|
||||||
|
void updateCellModel(){
|
||||||
|
if(updateable.size() > 0){
|
||||||
|
String targetKey = updateable.iterator().next();
|
||||||
|
updateable.remove(targetKey);
|
||||||
|
Vector3i worldPos = getVectorFromKey(targetKey);
|
||||||
|
if(
|
||||||
|
worldPos.x >= 0 &&
|
||||||
|
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.y >= 0 &&
|
||||||
|
worldPos.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.z >= 0 &&
|
||||||
|
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
// if(Math.abs(drawRadius + 1 - targetX) < physicsRadius && Math.abs(drawRadius + 1 - targetY) < physicsRadius){
|
||||||
|
// needsPhysics[targetX][targetY] = true;
|
||||||
|
// }
|
||||||
|
// int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius)); //Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
|
||||||
|
// int stride = Math.min(commonWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue));
|
||||||
|
// while(commonWorldData.getDynamicInterpolationRatio() % stride != 0){
|
||||||
|
// stride = stride + 1;
|
||||||
|
// }
|
||||||
|
keyCellMap.get(targetKey).destroy();
|
||||||
|
keyCellMap.get(targetKey).generateDrawableEntity();
|
||||||
|
}
|
||||||
|
drawable.add(targetKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean containsUnrequestedCell(){
|
||||||
|
return hasNotRequested.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsUndrawableCell(){
|
||||||
|
return undrawable.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsUpdateableCell(){
|
||||||
|
return updateable.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public int transformRealSpaceToCellSpace(double input){
|
||||||
|
return (int)(input / Globals.clientWorldData.getDynamicInterpolationRatio());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the valid set and adds all keys to invalid set
|
||||||
|
*/
|
||||||
|
public void invalidateAllCells(){
|
||||||
|
drawable.clear();
|
||||||
|
hasNotRequested.clear();
|
||||||
|
clearOutOfBoundsCells();
|
||||||
|
queueNewCells();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates whether the position of the player has changed and if so, invalidates and cleans up cells accordingly
|
||||||
|
* @param position The position of the player entity on current frame
|
||||||
|
*/
|
||||||
|
public void calculateDeltas(Vector3d position){
|
||||||
|
//check if any not requested cells no longer need to be requested
|
||||||
|
clearOutOfBoundsCells();
|
||||||
|
//check if any cells should be added
|
||||||
|
queueNewCells();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all cells outside of draw radius
|
||||||
|
*/
|
||||||
|
private void clearOutOfBoundsCells(){
|
||||||
|
Set<FluidDrawCell> cellsToRemove = new HashSet<FluidDrawCell>();
|
||||||
|
for(FluidDrawCell cell : cells){
|
||||||
|
Vector3d realPos = cell.getRealPos();
|
||||||
|
if(Globals.playerEntity != null && EntityUtils.getPosition(Globals.playerEntity).distance(realPos) > drawRadius){
|
||||||
|
cellsToRemove.add(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(FluidDrawCell cell : cellsToRemove){
|
||||||
|
cells.remove(cell);
|
||||||
|
String key = getCellKey(cell.worldPos.x, cell.worldPos.y, cell.worldPos.z);
|
||||||
|
hasNotRequested.remove(key);
|
||||||
|
drawable.remove(key);
|
||||||
|
undrawable.remove(key);
|
||||||
|
updateable.remove(key);
|
||||||
|
keyCellMap.remove(key);
|
||||||
|
hasRequested.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues new cells that are in bounds but not currently accounted for
|
||||||
|
*/
|
||||||
|
private void queueNewCells(){
|
||||||
|
if(Globals.playerEntity != null && Globals.clientWorldData != null){
|
||||||
|
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
|
for(int x = -(int)drawRadius; x < drawRadius; x = x + ChunkData.CHUNK_SIZE){
|
||||||
|
for(int y = -(int)drawRadius; y < drawRadius; y = y + ChunkData.CHUNK_SIZE){
|
||||||
|
for(int z = -(int)drawRadius; z < drawRadius; z = z + ChunkData.CHUNK_SIZE){
|
||||||
|
Vector3d newPos = new Vector3d(playerPos.x + x, playerPos.y + y, playerPos.z + z);
|
||||||
|
Vector3i worldPos = new Vector3i(
|
||||||
|
Globals.clientWorldData.convertRealToChunkSpace(newPos.x),
|
||||||
|
Globals.clientWorldData.convertRealToChunkSpace(newPos.y),
|
||||||
|
Globals.clientWorldData.convertRealToChunkSpace(newPos.z)
|
||||||
|
);
|
||||||
|
Vector3d chunkRealSpace = new Vector3d(
|
||||||
|
Globals.clientWorldData.convertChunkToRealSpace(worldPos.x),
|
||||||
|
Globals.clientWorldData.convertChunkToRealSpace(worldPos.y),
|
||||||
|
Globals.clientWorldData.convertChunkToRealSpace(worldPos.z)
|
||||||
|
);
|
||||||
|
if(
|
||||||
|
playerPos.distance(chunkRealSpace) < drawRadius &&
|
||||||
|
worldPos.x >= 0 &&
|
||||||
|
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.y >= 0 &&
|
||||||
|
worldPos.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.z >= 0 &&
|
||||||
|
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
String key = getCellKey(
|
||||||
|
Globals.clientWorldData.convertRealToChunkSpace(chunkRealSpace.x),
|
||||||
|
Globals.clientWorldData.convertRealToChunkSpace(chunkRealSpace.y),
|
||||||
|
Globals.clientWorldData.convertRealToChunkSpace(chunkRealSpace.z)
|
||||||
|
);
|
||||||
|
if(!keyCellMap.containsKey(key) && !hasNotRequested.contains(key) && !undrawable.contains(key) && !drawable.contains(key) &&
|
||||||
|
!hasRequested.contains(key)){
|
||||||
|
hasNotRequested.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates cells that need updating in this manager
|
||||||
|
*/
|
||||||
|
public void update(){
|
||||||
|
if(update){
|
||||||
|
if(containsUnrequestedCell() && !containsUndrawableCell()){
|
||||||
|
updateUnrequestedCell();
|
||||||
|
} else if(containsUndrawableCell()){
|
||||||
|
makeCellDrawable();
|
||||||
|
} else if(containsUpdateableCell()){
|
||||||
|
updateCellModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits a cell key into its constituent coordinates in array format.
|
||||||
|
* @param cellKey The cell key to split
|
||||||
|
* @return The coordinates in array format
|
||||||
|
*/
|
||||||
|
// private int[] splitKeyToCoordinates(String cellKey){
|
||||||
|
// int[] rVal = new int[3];
|
||||||
|
// String[] components = cellKey.split("_");
|
||||||
|
// for(int i = 0; i < 3; i++){
|
||||||
|
// rVal[i] = Integer.parseInt(components[i]);
|
||||||
|
// }
|
||||||
|
// return rVal;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public boolean coordsInPhysicsSpace(int worldX, int worldY){
|
||||||
|
return worldX <= cellX + physicsRadius && worldX >= cellX - physicsRadius && worldY <= cellY + physicsRadius && worldY >= cellY - physicsRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGenerateDrawables(boolean generate){
|
||||||
|
this.generateDrawables = generate;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
||||||
|
if(Globals.clientTerrainManager != null){
|
||||||
|
return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the chunk data at a given point
|
||||||
|
* @param worldX The world position x component of the cell
|
||||||
|
* @param worldY The world position y component of the cell
|
||||||
|
* @param worldZ The world position z component of the cell
|
||||||
|
* @return The chunk data at the specified points
|
||||||
|
*/
|
||||||
|
ChunkData getChunkDataAtPoint(int worldX, int worldY, int worldZ){
|
||||||
|
return Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldX,worldY,worldZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a unique key for the cell
|
||||||
|
* @param worldX The world position x component of the cell
|
||||||
|
* @param worldY The world position y component of the cell
|
||||||
|
* @param worldZ The world position z component of the cell
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
private String getCellKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a vector3i from the cell key
|
||||||
|
* @param key The cell key
|
||||||
|
* @return The vector3i containing the components of the cell key
|
||||||
|
*/
|
||||||
|
private Vector3i getVectorFromKey(String key){
|
||||||
|
String[] keyComponents = key.split("_");
|
||||||
|
return new Vector3i(Integer.parseInt(keyComponents[0]),Integer.parseInt(keyComponents[1]),Integer.parseInt(keyComponents[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a data cell as updateable (can be regenerated with a new model because the underlying data has changed)
|
||||||
|
* @param chunkX The chunk x coordinate
|
||||||
|
* @param chunkY The chunk y coordinate
|
||||||
|
* @param chunkZ The chunk z coordinate
|
||||||
|
*/
|
||||||
|
public void markUpdateable(int chunkX, int chunkY, int chunkZ){
|
||||||
|
updateable.add(getCellKey(chunkX, chunkY, chunkZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// public
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
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.EntityUtils;
|
||||||
|
import electrosphere.entity.types.fluid.FluidChunk;
|
||||||
|
import electrosphere.renderer.ShaderProgram;
|
||||||
|
import electrosphere.renderer.texture.Texture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author satellite
|
||||||
|
*/
|
||||||
|
public class FluidDrawCell {
|
||||||
|
//the position of the draw cell in world coordinates
|
||||||
|
Vector3i worldPos;
|
||||||
|
|
||||||
|
FluidChunkData data;
|
||||||
|
|
||||||
|
Entity modelEntity;
|
||||||
|
|
||||||
|
ShaderProgram program;
|
||||||
|
|
||||||
|
DBody physicsObject;
|
||||||
|
|
||||||
|
static Texture groundTextureOne = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
static Texture groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
static Texture groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
static Texture groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
|
||||||
|
static {
|
||||||
|
// groundTextureOne = new Texture("/Textures/Ground/GrassTileable.png");
|
||||||
|
// groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
// groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
// groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FluidDrawCell(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a drawcell object
|
||||||
|
*/
|
||||||
|
public static FluidDrawCell generateFluidCell(
|
||||||
|
Vector3i worldPos,
|
||||||
|
FluidChunkData data,
|
||||||
|
ShaderProgram program
|
||||||
|
){
|
||||||
|
FluidDrawCell rVal = new FluidDrawCell();
|
||||||
|
rVal.worldPos = worldPos;
|
||||||
|
rVal.program = program;
|
||||||
|
rVal.data = data;
|
||||||
|
System.out.println("Create cell");
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a drawable entity based on this chunk
|
||||||
|
*/
|
||||||
|
public void generateDrawableEntity(){
|
||||||
|
if(modelEntity != null){
|
||||||
|
Globals.clientScene.deregisterEntity(modelEntity);
|
||||||
|
}
|
||||||
|
modelEntity = FluidChunk.clientCreateFluidChunkEntity(data.getVoxelWeight(), data.getVoxelType());
|
||||||
|
for(Vector3i position : data.getModifiedPositions()){
|
||||||
|
Globals.clientFoliageManager.invalidateCell(worldPos, position);
|
||||||
|
}
|
||||||
|
data.resetModifiedPositions();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current chunk data for this draw cell
|
||||||
|
* @return The chunk data
|
||||||
|
*/
|
||||||
|
public FluidChunkData getData(){
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package electrosphere.client.fluid.editing;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for editing fluid from client side of things
|
||||||
|
*/
|
||||||
|
public class FluidEditing {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a fluid chunk edit. Basically has a sphere around the provided position that it attempts to add value to.
|
||||||
|
* @param position The position to perform the edit
|
||||||
|
* @param editMagnitude The magnitude of the edit to perform
|
||||||
|
* @param type The type of block to make all edited blocks
|
||||||
|
* @param weight The weight of the sphere to apply the edit to
|
||||||
|
*/
|
||||||
|
public static void editFluid(Vector3d position, float editMagnitude, int type, float weight){
|
||||||
|
if(position != null){
|
||||||
|
// Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestUseTerrainPaletteMessage(position.x, position.y, position.z, editMagnitude, weight, type));
|
||||||
|
//calculate kernel size
|
||||||
|
// int numPlacesToCheck = (int)((editMagnitude * 2 + 1) * (editMagnitude * 2 + 1) * (editMagnitude * 2 + 1));
|
||||||
|
// //create and fill in kernel of positions to check
|
||||||
|
// int[] xOffsetSet = new int[numPlacesToCheck];
|
||||||
|
// int[] yOffsetSet = new int[numPlacesToCheck];
|
||||||
|
// int[] zOffsetSet = new int[numPlacesToCheck];
|
||||||
|
// int i = 0;
|
||||||
|
// for(int x = -(int)editMagnitude; x <= (int)editMagnitude; x++){
|
||||||
|
// for(int y = -(int)editMagnitude; y <= (int)editMagnitude; y++){
|
||||||
|
// for(int z = -(int)editMagnitude; z <= (int)editMagnitude; z++){
|
||||||
|
// xOffsetSet[i] = x;
|
||||||
|
// yOffsetSet[i] = y;
|
||||||
|
// zOffsetSet[i] = z;
|
||||||
|
// i++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for(i = 0; i < numPlacesToCheck; i++){
|
||||||
|
// //calculate position of edit
|
||||||
|
// Vector3d offsetPos = new Vector3d(position).add(xOffsetSet[i],yOffsetSet[i],zOffsetSet[i]);
|
||||||
|
// Vector3i chunkPos = Globals.clientWorldData.convertRealToChunkSpace(offsetPos);
|
||||||
|
// Vector3i voxelPos = Globals.clientWorldData.convertRealToVoxelSpace(offsetPos);
|
||||||
|
// //get distance from true center point of sphere to current voxel position in world space
|
||||||
|
// float distance = (float)new Vector3d(Math.floor(offsetPos.x),Math.floor(offsetPos.y),Math.floor(offsetPos.z)).distance(position);
|
||||||
|
// float currentPositionMagnitude = editMagnitude - distance;
|
||||||
|
// ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkPos.x, chunkPos.y, chunkPos.z);
|
||||||
|
// if(
|
||||||
|
// voxelPos.x < ChunkData.CHUNK_SIZE &&
|
||||||
|
// voxelPos.y < ChunkData.CHUNK_SIZE &&
|
||||||
|
// voxelPos.z < ChunkData.CHUNK_SIZE &&
|
||||||
|
// currentPositionMagnitude > 0 &&
|
||||||
|
// data != null
|
||||||
|
// ){
|
||||||
|
// float current = data.getVoxelWeight()[voxelPos.x][voxelPos.y][voxelPos.z];
|
||||||
|
// //hard clamp so it doesn't go over 1
|
||||||
|
// float finalValue = Math.max(Math.min(current + weight,1),-1);
|
||||||
|
// Globals.clientTerrainManager.updateChunk(
|
||||||
|
// chunkPos.x, chunkPos.y, chunkPos.z,
|
||||||
|
// voxelPos.x, voxelPos.y, voxelPos.z,
|
||||||
|
// finalValue, 1
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,163 @@
|
|||||||
|
package electrosphere.client.fluid.manager;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.fluid.cache.ClientFluidCache;
|
||||||
|
import electrosphere.client.fluid.cache.FluidChunkData;
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.types.fluid.FluidChunkModelData;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
|
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||||
|
import electrosphere.renderer.Model;
|
||||||
|
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages fluid storage and access on the client
|
||||||
|
*/
|
||||||
|
public class ClientFluidManager {
|
||||||
|
|
||||||
|
//queues messages from server
|
||||||
|
List<TerrainMessage> messageQueue = new CopyOnWriteArrayList<TerrainMessage>();
|
||||||
|
|
||||||
|
//The interpolation ratio of fluid
|
||||||
|
public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
|
||||||
|
|
||||||
|
//caches chunks from server
|
||||||
|
static final int CACHE_SIZE = 50;
|
||||||
|
|
||||||
|
//used for caching the macro values
|
||||||
|
ClientFluidCache fluidCache;
|
||||||
|
|
||||||
|
//The world data for the client
|
||||||
|
ClientWorldData clientWorldData;
|
||||||
|
|
||||||
|
//The queue of fluid chunk data to be buffered to gpu
|
||||||
|
static List<FluidChunkGenQueueItem> fluidChunkGenerationQueue = new CopyOnWriteArrayList<FluidChunkGenQueueItem>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ClientFluidManager(){
|
||||||
|
fluidCache = new ClientFluidCache(CACHE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void handleMessages(){
|
||||||
|
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
|
||||||
|
for(TerrainMessage message : messageQueue){
|
||||||
|
messageQueue.remove(message);
|
||||||
|
switch(message.getMessageSubtype()){
|
||||||
|
case SENDCHUNKDATA: {
|
||||||
|
int[][][] values = new int[FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
float[][][] weights = new float[FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData());
|
||||||
|
FloatBuffer floatBuffer = buffer.asFloatBuffer();
|
||||||
|
for(int x = 0; x < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||||
|
for(int y = 0; y < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||||
|
for(int z = 0; z < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
|
||||||
|
weights[x][y][z] = floatBuffer.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntBuffer intView = buffer.asIntBuffer();
|
||||||
|
intView.position(floatBuffer.position());
|
||||||
|
for(int x = 0; x < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||||
|
for(int y = 0; y < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||||
|
for(int z = 0; z < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
|
||||||
|
values[x][y][z] = intView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FluidChunkData data = new FluidChunkData();
|
||||||
|
data.setVoxelType(values);
|
||||||
|
data.setVoxelWeight(weights);
|
||||||
|
fluidCache.addChunkDataToCache(
|
||||||
|
message.getworldX(), message.getworldY(), message.getworldZ(),
|
||||||
|
data
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
LoggerInterface.loggerEngine.WARNING("ClientFluidManager: unhandled network message of type" + message.getMessageSubtype());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(TerrainMessage message : bouncedMessages){
|
||||||
|
messageQueue.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachTerrainMessage(TerrainMessage message){
|
||||||
|
messageQueue.add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
||||||
|
return fluidCache.containsChunkDataAtWorldPoint(worldX, worldY, worldZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsChunkDataAtRealPoint(double x, double y, double z){
|
||||||
|
assert clientWorldData != null;
|
||||||
|
return fluidCache.containsChunkDataAtWorldPoint(
|
||||||
|
clientWorldData.convertRealToChunkSpace(x),
|
||||||
|
clientWorldData.convertRealToChunkSpace(y),
|
||||||
|
clientWorldData.convertRealToChunkSpace(z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the chunk data at a given world position
|
||||||
|
* @param worldX The x component of the world coordinate
|
||||||
|
* @param worldY The y component of the world coordinate
|
||||||
|
* @param worldZ The z component of the world coordinate
|
||||||
|
* @return The chunk data if it exists, otherwise null
|
||||||
|
*/
|
||||||
|
public FluidChunkData getChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
||||||
|
return fluidCache.getSubChunkDataAtPoint(worldX, worldY, worldZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the chunk data at a given world position
|
||||||
|
* @param worldPos The world position as a joml vector
|
||||||
|
* @return The chunk data if it exists, otherwise null
|
||||||
|
*/
|
||||||
|
public FluidChunkData getChunkDataAtWorldPoint(Vector3i worldPos){
|
||||||
|
return fluidCache.getSubChunkDataAtPoint(worldPos.x, worldPos.y, worldPos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues a fluid chunk to be pushed to GPU based on chunk data
|
||||||
|
* @param data The chunk data (triangles, normals, etc)
|
||||||
|
* @return The model path that is promised to eventually reflect the fluid model when it makes it to gpu
|
||||||
|
*/
|
||||||
|
public static String queueFluidGridGeneration(FluidChunkModelData data){
|
||||||
|
String promisedHash = "";
|
||||||
|
UUID newUUID = UUID.randomUUID();
|
||||||
|
promisedHash = newUUID.toString();
|
||||||
|
FluidChunkGenQueueItem queueItem = new FluidChunkGenQueueItem(data, promisedHash);
|
||||||
|
fluidChunkGenerationQueue.add(queueItem);
|
||||||
|
return promisedHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes all fluid data in queue to the gpu and registers the resulting models
|
||||||
|
*/
|
||||||
|
public static void generateFluidChunkGeometry(){
|
||||||
|
for(FluidChunkGenQueueItem queueItem : fluidChunkGenerationQueue){
|
||||||
|
Model fluidModel = FluidChunkModelGeneration.generateFluidModel(queueItem.getData());
|
||||||
|
Globals.assetManager.registerModelToSpecificString(fluidModel, queueItem.getPromisedHash());
|
||||||
|
}
|
||||||
|
fluidChunkGenerationQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package electrosphere.client.fluid.manager;
|
||||||
|
|
||||||
|
import electrosphere.entity.types.fluid.FluidChunkModelData;
|
||||||
|
|
||||||
|
public class FluidChunkGenQueueItem {
|
||||||
|
|
||||||
|
FluidChunkModelData data;
|
||||||
|
String promisedHash;
|
||||||
|
|
||||||
|
public FluidChunkGenQueueItem(FluidChunkModelData data, String promisedHash){
|
||||||
|
this.data = data;
|
||||||
|
this.promisedHash = promisedHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidChunkModelData getData(){
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPromisedHash(){
|
||||||
|
return this.promisedHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ import org.lwjgl.glfw.GLFWErrorCallback;
|
|||||||
import electrosphere.audio.AudioEngine;
|
import electrosphere.audio.AudioEngine;
|
||||||
import electrosphere.auth.AuthenticationManager;
|
import electrosphere.auth.AuthenticationManager;
|
||||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||||
|
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||||
import electrosphere.client.player.ClientPlayerData;
|
import electrosphere.client.player.ClientPlayerData;
|
||||||
import electrosphere.client.scene.ClientSceneWrapper;
|
import electrosphere.client.scene.ClientSceneWrapper;
|
||||||
@ -273,6 +274,9 @@ public class Globals {
|
|||||||
|
|
||||||
//client terrain manager
|
//client terrain manager
|
||||||
public static ClientTerrainManager clientTerrainManager;
|
public static ClientTerrainManager clientTerrainManager;
|
||||||
|
|
||||||
|
//client fluid manager
|
||||||
|
public static ClientFluidManager clientFluidManager;
|
||||||
|
|
||||||
//client player data
|
//client player data
|
||||||
public static ClientPlayerData clientPlayerData = new ClientPlayerData();
|
public static ClientPlayerData clientPlayerData = new ClientPlayerData();
|
||||||
@ -439,8 +443,11 @@ public class Globals {
|
|||||||
//init default shaderProgram
|
//init default shaderProgram
|
||||||
defaultMeshShader = ShaderProgram.smart_assemble_shader(false,true);
|
defaultMeshShader = ShaderProgram.smart_assemble_shader(false,true);
|
||||||
//init terrain shader program
|
//init terrain shader program
|
||||||
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain/terrain.vs", "/Shaders/terrain/terrain.fs");
|
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain.vs", "/Shaders/terrain2/terrain.fs");
|
||||||
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
|
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
|
||||||
|
//init fluid shader program
|
||||||
|
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");
|
||||||
|
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");
|
||||||
//init skybox
|
//init skybox
|
||||||
assetManager.registerModelToSpecificString(RenderUtils.createSkyboxModel(null), AssetDataStrings.ASSET_STRING_SKYBOX_BASIC);
|
assetManager.registerModelToSpecificString(RenderUtils.createSkyboxModel(null), AssetDataStrings.ASSET_STRING_SKYBOX_BASIC);
|
||||||
//init leaves
|
//init leaves
|
||||||
|
|||||||
@ -29,6 +29,11 @@ public class EntityDataStrings {
|
|||||||
Terrain Entity
|
Terrain Entity
|
||||||
*/
|
*/
|
||||||
public static final String TERRAIN_IS_TERRAIN = "terrainEntity";
|
public static final String TERRAIN_IS_TERRAIN = "terrainEntity";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fluid Entity
|
||||||
|
*/
|
||||||
|
public static final String FLUID_IS_FLUID = "fluidEntity";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
package electrosphere.entity.types.fluid;
|
||||||
|
|
||||||
|
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityCreationUtils;
|
||||||
|
import electrosphere.entity.EntityDataStrings;
|
||||||
|
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a fluid chunk entity
|
||||||
|
*/
|
||||||
|
public class FluidChunk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a client fluid chunk based on weights and values provided
|
||||||
|
* @param weights The fluid weights
|
||||||
|
* @param values The values (block types)
|
||||||
|
* @return The fluid chunk entity
|
||||||
|
*/
|
||||||
|
public static Entity clientCreateFluidChunkEntity(float[][][] weights, int[][][] values){
|
||||||
|
|
||||||
|
FluidChunkModelData data = FluidChunkModelGeneration.generateFluidChunkData(weights, values);
|
||||||
|
String modelPath = ClientFluidManager.queueFluidGridGeneration(data);
|
||||||
|
|
||||||
|
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
|
||||||
|
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
|
||||||
|
// if(data.vertices.size() > 0 && levelOfDetail < 1){
|
||||||
|
// PhysicsUtils.clientAttachTerrainChunkRigidBody(rVal, data);
|
||||||
|
// }
|
||||||
|
|
||||||
|
rVal.putData(EntityDataStrings.FLUID_IS_FLUID, true);
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package electrosphere.entity.types.fluid;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FluidChunkModelData {
|
||||||
|
|
||||||
|
List<Float> vertices;
|
||||||
|
List<Float> normals;
|
||||||
|
List<Integer> faceElements;
|
||||||
|
List<Float> uvs;
|
||||||
|
|
||||||
|
public FluidChunkModelData(List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs){
|
||||||
|
this.vertices = vertices;
|
||||||
|
this.normals = normals;
|
||||||
|
this.faceElements = faceElements;
|
||||||
|
this.uvs = uvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Float> getVertices(){
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Float> getNormals(){
|
||||||
|
return normals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getFaceElements(){
|
||||||
|
return faceElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Float> getUVs(){
|
||||||
|
return uvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,831 @@
|
|||||||
|
package electrosphere.renderer.meshgen;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.types.fluid.FluidChunkModelData;
|
||||||
|
import electrosphere.renderer.Material;
|
||||||
|
import electrosphere.renderer.Mesh;
|
||||||
|
import electrosphere.renderer.Model;
|
||||||
|
import electrosphere.renderer.ShaderProgram;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||||
|
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||||
|
|
||||||
|
public class FluidChunkModelGeneration {
|
||||||
|
|
||||||
|
//http://paulbourke.net/geometry/polygonise/
|
||||||
|
|
||||||
|
static int edgeTable[]={
|
||||||
|
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
|
||||||
|
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
|
||||||
|
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
|
||||||
|
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
|
||||||
|
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
|
||||||
|
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
|
||||||
|
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
|
||||||
|
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
|
||||||
|
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
|
||||||
|
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
|
||||||
|
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
|
||||||
|
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
|
||||||
|
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
|
||||||
|
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
|
||||||
|
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
|
||||||
|
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
|
||||||
|
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
|
||||||
|
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
|
||||||
|
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
|
||||||
|
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
|
||||||
|
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
|
||||||
|
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
|
||||||
|
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
|
||||||
|
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
|
||||||
|
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
|
||||||
|
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
|
||||||
|
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
|
||||||
|
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
|
||||||
|
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
|
||||||
|
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
|
||||||
|
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
|
||||||
|
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
|
||||||
|
};
|
||||||
|
|
||||||
|
//256 by 16
|
||||||
|
static int triTable[][] = {
|
||||||
|
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
|
||||||
|
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
|
||||||
|
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
|
||||||
|
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
|
||||||
|
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
|
||||||
|
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
|
||||||
|
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
|
||||||
|
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
|
||||||
|
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
|
||||||
|
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
|
||||||
|
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
|
||||||
|
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
|
||||||
|
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
|
||||||
|
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
|
||||||
|
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
|
||||||
|
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
|
||||||
|
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
|
||||||
|
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
|
||||||
|
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
|
||||||
|
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
|
||||||
|
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
|
||||||
|
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
|
||||||
|
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
|
||||||
|
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
|
||||||
|
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
|
||||||
|
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
|
||||||
|
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
|
||||||
|
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
|
||||||
|
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
|
||||||
|
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
|
||||||
|
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
|
||||||
|
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
|
||||||
|
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
|
||||||
|
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
|
||||||
|
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
|
||||||
|
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
|
||||||
|
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
|
||||||
|
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
|
||||||
|
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
|
||||||
|
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
|
||||||
|
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
|
||||||
|
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
|
||||||
|
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
|
||||||
|
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
|
||||||
|
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
|
||||||
|
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
|
||||||
|
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
|
||||||
|
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
|
||||||
|
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
|
||||||
|
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
|
||||||
|
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
|
||||||
|
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
|
||||||
|
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
|
||||||
|
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
|
||||||
|
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
|
||||||
|
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
|
||||||
|
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
|
||||||
|
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
|
||||||
|
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
|
||||||
|
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
|
||||||
|
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
|
||||||
|
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
|
||||||
|
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
|
||||||
|
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
|
||||||
|
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
|
||||||
|
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
|
||||||
|
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
|
||||||
|
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
|
||||||
|
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
|
||||||
|
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
|
||||||
|
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
|
||||||
|
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
|
||||||
|
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
|
||||||
|
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
|
||||||
|
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
|
||||||
|
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
|
||||||
|
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
|
||||||
|
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
|
||||||
|
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
|
||||||
|
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
|
||||||
|
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
|
||||||
|
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
|
||||||
|
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
|
||||||
|
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
|
||||||
|
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
|
||||||
|
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
|
||||||
|
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
|
||||||
|
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
|
||||||
|
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
|
||||||
|
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
|
||||||
|
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
|
||||||
|
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
|
||||||
|
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
|
||||||
|
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
|
||||||
|
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
|
||||||
|
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
|
||||||
|
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
|
||||||
|
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
|
||||||
|
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
|
||||||
|
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
|
||||||
|
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
|
||||||
|
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
|
||||||
|
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
|
||||||
|
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
|
||||||
|
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
|
||||||
|
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
|
||||||
|
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
|
||||||
|
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
|
||||||
|
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||||
|
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final byte[] BLOCK_PICK_BITS_BY_VERT_INDEX = new byte[]{
|
||||||
|
(byte)0x67,
|
||||||
|
(byte)0x26,
|
||||||
|
(byte)0x23,
|
||||||
|
(byte)0x37,
|
||||||
|
(byte)0x45,
|
||||||
|
(byte)0x04,
|
||||||
|
(byte)0x01,
|
||||||
|
(byte)0x15,
|
||||||
|
(byte)0x57,
|
||||||
|
(byte)0x46,
|
||||||
|
(byte)0x02,
|
||||||
|
(byte)0x13
|
||||||
|
};
|
||||||
|
|
||||||
|
static class Triangle {
|
||||||
|
int[] indices = new int[3]; //array of size 3
|
||||||
|
|
||||||
|
public Triangle(int index0, int index1, int index2){
|
||||||
|
indices[0] = index0;
|
||||||
|
indices[1] = index1;
|
||||||
|
indices[2] = index2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GridCell {
|
||||||
|
Vector3f[] points = new Vector3f[8]; //array of size 8
|
||||||
|
double[] val = new double[8]; //array of size 8
|
||||||
|
public void setValues(
|
||||||
|
Vector3f p1, Vector3f p2, Vector3f p3, Vector3f p4,
|
||||||
|
Vector3f p5, Vector3f p6, Vector3f p7, Vector3f p8,
|
||||||
|
double val1, double val2, double val3, double val4,
|
||||||
|
double val5, double val6, double val7, double val8
|
||||||
|
){
|
||||||
|
points[0] = p1; points[1] = p2; points[2] = p3; points[3] = p4;
|
||||||
|
points[4] = p5; points[5] = p6; points[6] = p7; points[7] = p8;
|
||||||
|
val[0] = val1; val[1] = val2; val[2] = val3; val[3] = val4;
|
||||||
|
val[4] = val5; val[5] = val6; val[6] = val7; val[7] = val8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static ShaderProgram fluidChunkShaderProgram = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected static int polygonize(
|
||||||
|
GridCell grid,
|
||||||
|
double isolevel,
|
||||||
|
List<Triangle> triangles,
|
||||||
|
Map<String,Integer> vertMap,
|
||||||
|
List<Vector3f> verts,
|
||||||
|
List<Vector3f> normals,
|
||||||
|
List<Integer> trianglesSharingVert
|
||||||
|
){
|
||||||
|
int i;
|
||||||
|
int ntriang;
|
||||||
|
int cubeIndex = 0;
|
||||||
|
Vector3f[] vertList = new Vector3f[12];
|
||||||
|
|
||||||
|
//get lookup key (index) for edge table
|
||||||
|
//edge table tells us which vertices are inside of the surface
|
||||||
|
if (grid.val[0] < isolevel) cubeIndex |= 1;
|
||||||
|
if (grid.val[1] < isolevel) cubeIndex |= 2;
|
||||||
|
if (grid.val[2] < isolevel) cubeIndex |= 4;
|
||||||
|
if (grid.val[3] < isolevel) cubeIndex |= 8;
|
||||||
|
if (grid.val[4] < isolevel) cubeIndex |= 16;
|
||||||
|
if (grid.val[5] < isolevel) cubeIndex |= 32;
|
||||||
|
if (grid.val[6] < isolevel) cubeIndex |= 64;
|
||||||
|
if (grid.val[7] < isolevel) cubeIndex |= 128;
|
||||||
|
|
||||||
|
//Cube is entirely in/out of the surface
|
||||||
|
if (edgeTable[cubeIndex] == 0)
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
//instead of having all intersections be perfectly at the midpoint,
|
||||||
|
//for each edge this code calculates where along the edge to place the vertex
|
||||||
|
//this should dramatically smooth the surface
|
||||||
|
if ((edgeTable[cubeIndex] & 1) > 0)
|
||||||
|
vertList[0] =
|
||||||
|
VertexInterp(isolevel,grid.points[0],grid.points[1],grid.val[0],grid.val[1]);
|
||||||
|
if ((edgeTable[cubeIndex] & 2) > 0)
|
||||||
|
vertList[1] =
|
||||||
|
VertexInterp(isolevel,grid.points[1],grid.points[2],grid.val[1],grid.val[2]);
|
||||||
|
if ((edgeTable[cubeIndex] & 4) > 0)
|
||||||
|
vertList[2] =
|
||||||
|
VertexInterp(isolevel,grid.points[2],grid.points[3],grid.val[2],grid.val[3]);
|
||||||
|
if ((edgeTable[cubeIndex] & 8) > 0)
|
||||||
|
vertList[3] =
|
||||||
|
VertexInterp(isolevel,grid.points[3],grid.points[0],grid.val[3],grid.val[0]);
|
||||||
|
if ((edgeTable[cubeIndex] & 16) > 0)
|
||||||
|
vertList[4] =
|
||||||
|
VertexInterp(isolevel,grid.points[4],grid.points[5],grid.val[4],grid.val[5]);
|
||||||
|
if ((edgeTable[cubeIndex] & 32) > 0)
|
||||||
|
vertList[5] =
|
||||||
|
VertexInterp(isolevel,grid.points[5],grid.points[6],grid.val[5],grid.val[6]);
|
||||||
|
if ((edgeTable[cubeIndex] & 64) > 0)
|
||||||
|
vertList[6] =
|
||||||
|
VertexInterp(isolevel,grid.points[6],grid.points[7],grid.val[6],grid.val[7]);
|
||||||
|
if ((edgeTable[cubeIndex] & 128) > 0)
|
||||||
|
vertList[7] =
|
||||||
|
VertexInterp(isolevel,grid.points[7],grid.points[4],grid.val[7],grid.val[4]);
|
||||||
|
if ((edgeTable[cubeIndex] & 256) > 0)
|
||||||
|
vertList[8] =
|
||||||
|
VertexInterp(isolevel,grid.points[0],grid.points[4],grid.val[0],grid.val[4]);
|
||||||
|
if ((edgeTable[cubeIndex] & 512) > 0)
|
||||||
|
vertList[9] =
|
||||||
|
VertexInterp(isolevel,grid.points[1],grid.points[5],grid.val[1],grid.val[5]);
|
||||||
|
if ((edgeTable[cubeIndex] & 1024) > 0)
|
||||||
|
vertList[10] =
|
||||||
|
VertexInterp(isolevel,grid.points[2],grid.points[6],grid.val[2],grid.val[6]);
|
||||||
|
if ((edgeTable[cubeIndex] & 2048) > 0)
|
||||||
|
vertList[11] =
|
||||||
|
VertexInterp(isolevel,grid.points[3],grid.points[7],grid.val[3],grid.val[7]);
|
||||||
|
|
||||||
|
//Create the triangle
|
||||||
|
ntriang = 0;
|
||||||
|
for (i=0; triTable[cubeIndex][i]!=-1; i+=3) {
|
||||||
|
//
|
||||||
|
// Triangles calculation
|
||||||
|
//
|
||||||
|
//get indices
|
||||||
|
Vector3f vert0 = vertList[triTable[cubeIndex][i+0]];
|
||||||
|
Vector3f vert1 = vertList[triTable[cubeIndex][i+1]];
|
||||||
|
Vector3f vert2 = vertList[triTable[cubeIndex][i+2]];
|
||||||
|
int index0 = getVertIndex(vert0,vertMap,verts);
|
||||||
|
int index1 = getVertIndex(vert1,vertMap,verts);
|
||||||
|
int index2 = getVertIndex(vert2,vertMap,verts);
|
||||||
|
|
||||||
|
//add 0's to normals until it matches vert count
|
||||||
|
while(trianglesSharingVert.size() < verts.size()){
|
||||||
|
trianglesSharingVert.add(0);
|
||||||
|
normals.add(new Vector3f());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//add new triangle
|
||||||
|
Triangle newTriangle = new Triangle(index0,index1,index2);
|
||||||
|
triangles.add(newTriangle);
|
||||||
|
ntriang++;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Normals calculation
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//calculate normal for new triangle
|
||||||
|
Vector3f u = verts.get(index1).sub(verts.get(index0), new Vector3f());
|
||||||
|
Vector3f v = verts.get(index2).sub(verts.get(index1), new Vector3f());
|
||||||
|
Vector3f n = new Vector3f(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x).normalize();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//for each vertex, average the new normal with the normals that are already there
|
||||||
|
int trianglesSharingIndex0 = trianglesSharingVert.get(index0);
|
||||||
|
//calculate proportion of each normal
|
||||||
|
float oldProportion = trianglesSharingIndex0 / (float)(trianglesSharingIndex0 + 1);
|
||||||
|
float newProportion = 1.0f / (float)(trianglesSharingIndex0 + 1);
|
||||||
|
//increment number of triangles sharing vert
|
||||||
|
trianglesSharingVert.set(index0, trianglesSharingIndex0 + 1);
|
||||||
|
|
||||||
|
Vector3f currentNormal = normals.get(index0);
|
||||||
|
currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion);
|
||||||
|
normals.get(index0).set(currentNormal);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int trianglesSharingIndex1 = trianglesSharingVert.get(index1);
|
||||||
|
//calculate proportion of each normal
|
||||||
|
oldProportion = trianglesSharingIndex1 / (float)(trianglesSharingIndex1 + 1);
|
||||||
|
newProportion = 1.0f / (float)(trianglesSharingIndex1 + 1);
|
||||||
|
//increment number of triangles sharing vert
|
||||||
|
trianglesSharingVert.set(index1, trianglesSharingIndex1 + 1);
|
||||||
|
|
||||||
|
currentNormal = normals.get(index1);
|
||||||
|
currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion);
|
||||||
|
normals.get(index1).set(currentNormal);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int trianglesSharingIndex2 = trianglesSharingVert.get(index2);
|
||||||
|
//calculate proportion of each normal
|
||||||
|
oldProportion = trianglesSharingIndex2 / (float)(trianglesSharingIndex2 + 1);
|
||||||
|
newProportion = 1.0f / (float)(trianglesSharingIndex2 + 1);
|
||||||
|
//increment number of triangles sharing vert
|
||||||
|
trianglesSharingVert.set(index2, trianglesSharingIndex2 + 1);
|
||||||
|
|
||||||
|
currentNormal = normals.get(index2);
|
||||||
|
currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion);
|
||||||
|
normals.get(index2).set(currentNormal);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return(ntriang);
|
||||||
|
}
|
||||||
|
|
||||||
|
//interpolates the location that the edge gets cut based on the magnitudes of the scalars of the vertices at either end of the edge
|
||||||
|
static Vector3f VertexInterp(double isolevel, Vector3f p1, Vector3f p2, double valp1, double valp2){
|
||||||
|
double mu;
|
||||||
|
float x, y, z;
|
||||||
|
|
||||||
|
if (Math.abs(isolevel-valp1) < 0.00001)
|
||||||
|
return(p1);
|
||||||
|
if (Math.abs(isolevel-valp2) < 0.00001)
|
||||||
|
return(p2);
|
||||||
|
if (Math.abs(valp1-valp2) < 0.00001)
|
||||||
|
return(p1);
|
||||||
|
mu = (isolevel - valp1) / (valp2 - valp1);
|
||||||
|
x = (float)(p1.x + mu * (p2.x - p1.x));
|
||||||
|
y = (float)(p1.y + mu * (p2.y - p1.y));
|
||||||
|
z = (float)(p1.z + mu * (p2.z - p1.z));
|
||||||
|
|
||||||
|
return new Vector3f(x,y,z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FluidChunkModelData generateFluidChunkData(float[][][] weightGrid, int[][][] typeGrid){
|
||||||
|
|
||||||
|
// 5 6
|
||||||
|
// +-------------+ +-----5-------+ ^ Y
|
||||||
|
// / | / | / | /| | _
|
||||||
|
// / | / | 4 9 6 10 | /\ Z
|
||||||
|
// 4 +-----+-------+ 7 | +-----+7------+ | | /
|
||||||
|
// | 1 +-------+-----+ 2 | +-----1-+-----+ | /
|
||||||
|
// | / | / 8 0 11 2 | /
|
||||||
|
// | / | / | / | / |/
|
||||||
|
// 0 +-------------+ 3 +------3------+ +---------------> X
|
||||||
|
|
||||||
|
//the current grid cell
|
||||||
|
GridCell currentCell = new GridCell();
|
||||||
|
//the list of all triangles
|
||||||
|
List<Triangle> triangles = new LinkedList<Triangle>();
|
||||||
|
//the map of vertex to index
|
||||||
|
Map<String,Integer> vertMap = new HashMap<String,Integer>();
|
||||||
|
//the list of all verts
|
||||||
|
List<Vector3f> verts = new LinkedList<Vector3f>();
|
||||||
|
//the list of all normals
|
||||||
|
List<Vector3f> normals = new LinkedList<Vector3f>();
|
||||||
|
//the list of number of triangles that share a vert
|
||||||
|
List<Integer> trianglesSharingVert = new LinkedList<Integer>();
|
||||||
|
//List of elements in order
|
||||||
|
List<Integer> faceElements = new LinkedList<Integer>();
|
||||||
|
//List of UVs
|
||||||
|
List<Float> UVs = new LinkedList<Float>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for(int x = 0; x < weightGrid.length - 1; x++){
|
||||||
|
for(int y = 0; y < weightGrid[0].length - 1; y++){
|
||||||
|
for(int z = 0; z < weightGrid[0][0].length - 1; z++){
|
||||||
|
//push the current cell's values into the gridcell
|
||||||
|
currentCell.setValues(
|
||||||
|
new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
|
||||||
|
new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0),
|
||||||
|
weightGrid[x+0][y+0][z+0], weightGrid[x+0][y+0][z+1], weightGrid[x+1][y+0][z+1], weightGrid[x+1][y+0][z+0],
|
||||||
|
weightGrid[x+0][y+1][z+0], weightGrid[x+0][y+1][z+1], weightGrid[x+1][y+1][z+1], weightGrid[x+1][y+1][z+0]
|
||||||
|
);
|
||||||
|
//polygonize the current gridcell
|
||||||
|
polygonize(currentCell, 0, triangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//all verts in order, flattened as an array of floats instead of vecs
|
||||||
|
List<Float> vertsFlat = new LinkedList<Float>();
|
||||||
|
//all normals in order, flattened as an array of floats instead of vecs
|
||||||
|
List<Float> normalsFlat = new LinkedList<Float>();
|
||||||
|
//all elements of faces in order
|
||||||
|
List<Integer> elementsFlat = new LinkedList<Integer>();
|
||||||
|
|
||||||
|
//flatten verts + normals
|
||||||
|
for(Vector3f vert : verts){
|
||||||
|
vertsFlat.add(vert.x);
|
||||||
|
vertsFlat.add(vert.y);
|
||||||
|
vertsFlat.add(vert.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Vector3f normal : normals){
|
||||||
|
normalsFlat.add(normal.x);
|
||||||
|
normalsFlat.add(normal.y);
|
||||||
|
normalsFlat.add(normal.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(Triangle triangle : triangles){
|
||||||
|
elementsFlat.add(triangle.indices[0]);
|
||||||
|
elementsFlat.add(triangle.indices[1]);
|
||||||
|
elementsFlat.add(triangle.indices[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] temp = new float[3];
|
||||||
|
int i = 0;
|
||||||
|
for(Vector3f normal : normals){
|
||||||
|
Vector3f vert = verts.get(i);
|
||||||
|
|
||||||
|
float absX = Math.abs(normal.x);
|
||||||
|
float absY = Math.abs(normal.y);
|
||||||
|
float absZ = Math.abs(normal.z);
|
||||||
|
|
||||||
|
float uvX = vert.z * absX + vert.x * absY + vert.x * absZ;
|
||||||
|
float uvY = vert.y * absX + vert.z * absY + vert.y * absZ;
|
||||||
|
temp[0] = uvX;
|
||||||
|
temp[1] = uvY;
|
||||||
|
|
||||||
|
// if(absX >= absZ && absX >= absY){
|
||||||
|
// temp[0] = normal.z / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ));
|
||||||
|
// temp[1] = normal.y / 2.0f + 0.5f + vert.x * (absY / (absX + absY)) + vert.y * (absX / (absX + absY));
|
||||||
|
// } else if(absZ >= absX && absZ >= absY){
|
||||||
|
// temp[0] = normal.x / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ));
|
||||||
|
// temp[1] = normal.y / 2.0f + 0.5f + vert.z * (absY / (absZ + absY)) + vert.y * (absZ / (absZ + absY));
|
||||||
|
// } else if(absY >= absX && absY >= absZ){
|
||||||
|
// temp[0] = normal.x / 2.0f + 0.5f + vert.y * (absX / (absX + absY)) + vert.x * (absY / (absX + absY));
|
||||||
|
// temp[1] = normal.z / 2.0f + 0.5f + vert.y * (absZ / (absZ + absY)) + vert.z * (absY / (absZ + absY));
|
||||||
|
// } else {
|
||||||
|
// temp[0] = vert.x / 1.5f + vert.z / 1.5f;
|
||||||
|
// temp[1] = vert.y / 1.5f + vert.z / 1.5f;
|
||||||
|
// }
|
||||||
|
i++;
|
||||||
|
UVs.add(temp[0]);
|
||||||
|
UVs.add(temp[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
|
||||||
|
FluidChunkModelData rVal = new FluidChunkModelData(vertsFlat, normalsFlat, elementsFlat, UVs);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a mesh based on a fluidchunkdata object
|
||||||
|
* @param data The fluid chunk data object
|
||||||
|
* @return The mesh
|
||||||
|
*/
|
||||||
|
protected static Mesh generateFluidMesh(FluidChunkModelData data){
|
||||||
|
|
||||||
|
Mesh mesh = new Mesh();
|
||||||
|
|
||||||
|
|
||||||
|
mesh.mesh = null;
|
||||||
|
|
||||||
|
//
|
||||||
|
// VAO
|
||||||
|
//
|
||||||
|
mesh.vertexArrayObject = glGenVertexArrays();
|
||||||
|
glBindVertexArray(mesh.vertexArrayObject);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//Buffer data to GPU
|
||||||
|
//
|
||||||
|
|
||||||
|
try {
|
||||||
|
mesh.vertexCount = data.getVertices().size() / 3;
|
||||||
|
FloatBuffer VertexArrayBufferData = BufferUtils.createFloatBuffer(mesh.vertexCount * 3);
|
||||||
|
float[] temp = new float[3];
|
||||||
|
for(float vertValue : data.getVertices()){
|
||||||
|
VertexArrayBufferData.put(vertValue);
|
||||||
|
}
|
||||||
|
VertexArrayBufferData.flip();
|
||||||
|
mesh.buffer_vertices(VertexArrayBufferData, 3);
|
||||||
|
} catch (NullPointerException ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FACES
|
||||||
|
//
|
||||||
|
mesh.faceCount = data.getFaceElements().size() / 3;
|
||||||
|
mesh.elementCount = data.getFaceElements().size();
|
||||||
|
try {
|
||||||
|
IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(mesh.elementCount);
|
||||||
|
int[] temp = new int[3];
|
||||||
|
for(int element : data.getFaceElements()){
|
||||||
|
elementArrayBufferData.put(element);
|
||||||
|
}
|
||||||
|
elementArrayBufferData.flip();
|
||||||
|
mesh.buffer_faces(elementArrayBufferData);
|
||||||
|
} catch (NullPointerException ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// NORMALS
|
||||||
|
//
|
||||||
|
try {
|
||||||
|
mesh.normalCount = data.getNormals().size() / 3;
|
||||||
|
FloatBuffer NormalArrayBufferData;
|
||||||
|
if(mesh.normalCount > 0){
|
||||||
|
NormalArrayBufferData = BufferUtils.createFloatBuffer(mesh.normalCount * 3);
|
||||||
|
float[] temp = new float[3];
|
||||||
|
for(float normalValue : data.getNormals()){
|
||||||
|
NormalArrayBufferData.put(normalValue);
|
||||||
|
}
|
||||||
|
NormalArrayBufferData.flip();
|
||||||
|
mesh.buffer_normals(NormalArrayBufferData, 3);
|
||||||
|
}
|
||||||
|
} catch (NullPointerException ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TEXTURE COORDINATES
|
||||||
|
//
|
||||||
|
try {
|
||||||
|
mesh.textureCoordCount = data.getUVs().size() / 2;
|
||||||
|
FloatBuffer TextureArrayBufferData;
|
||||||
|
if(mesh.textureCoordCount > 0){
|
||||||
|
TextureArrayBufferData = BufferUtils.createFloatBuffer(mesh.textureCoordCount * 2);
|
||||||
|
float[] temp = new float[2];
|
||||||
|
for(float uvValue : data.getUVs()){
|
||||||
|
TextureArrayBufferData.put(uvValue);
|
||||||
|
}
|
||||||
|
TextureArrayBufferData.flip();
|
||||||
|
mesh.buffer_texture_coords(TextureArrayBufferData, 2);
|
||||||
|
}
|
||||||
|
} catch (NullPointerException ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
mesh.nodeID = "fluidChunk";
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a model based on a fluidchunkdata object
|
||||||
|
* @param data The fluid chunk data object
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model generateFluidModel(FluidChunkModelData data){
|
||||||
|
Model rVal = new Model();
|
||||||
|
rVal.meshes = new ArrayList<Mesh>();
|
||||||
|
Mesh m = generateFluidMesh(data);
|
||||||
|
|
||||||
|
|
||||||
|
Material groundMat = new Material();
|
||||||
|
groundMat.set_diffuse("/Textures/Ground/Dirt1.png");
|
||||||
|
groundMat.set_specular("/Textures/Ground/Dirt1.png");
|
||||||
|
Globals.assetManager.addTexturePathtoQueue("/Textures/Ground/Dirt1.png");
|
||||||
|
m.setMaterial(groundMat);
|
||||||
|
|
||||||
|
m.setShader(FluidChunkModelGeneration.fluidChunkShaderProgram);
|
||||||
|
m.parent = rVal;
|
||||||
|
|
||||||
|
rVal.meshes.add(m);
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: more optimal key creation
|
||||||
|
private static String getVertKeyFromPoints(float x, float y, float z){
|
||||||
|
return x + "_" + y + "_" + z;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getVertIndex(Vector3f vert, Map<String,Integer> vertMap, List<Vector3f> verts){
|
||||||
|
int rVal = -1;
|
||||||
|
String vertKey = getVertKeyFromPoints(vert.x,vert.y,vert.z);
|
||||||
|
if(vertMap.containsKey(vertKey)){
|
||||||
|
return vertMap.get(vertKey);
|
||||||
|
} else {
|
||||||
|
rVal = verts.size();
|
||||||
|
verts.add(vert);
|
||||||
|
vertMap.put(vertKey,rVal);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3f averageNormals(Vector3f normal0, float proportion0, Vector3f normal1, float proportion1){
|
||||||
|
Vector3f rVal = new Vector3f(normal0);
|
||||||
|
rVal = rVal.mul(proportion0).add(new Vector3f(normal1).mul(proportion1));
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user