remove deprecated foliage manager
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
097c23ef28
commit
d7329210b0
@ -1,3 +1,3 @@
|
||||
#maven.buildNumber.plugin properties file
|
||||
#Thu Mar 27 17:44:45 EDT 2025
|
||||
buildNumber=607
|
||||
#Thu Mar 27 18:17:28 EDT 2025
|
||||
buildNumber=608
|
||||
|
||||
@ -1343,6 +1343,7 @@ Increase number of invalid openAL IDs
|
||||
Fix audio engine not cleaning up audio sources
|
||||
More accurate block test types
|
||||
Block meshgen work
|
||||
Delete deprecated foliage manager
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,165 +0,0 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
|
||||
@Deprecated
|
||||
/**
|
||||
* Manages ambient foliage (grass, small plants, etc) that should be shown, typically instanced
|
||||
*/
|
||||
public class ClientFoliageManager {
|
||||
|
||||
//Used to prevent concurrent usage of grassEntities set
|
||||
boolean ready = false;
|
||||
|
||||
/**
|
||||
* The target density for placing foliage
|
||||
*/
|
||||
float targetDensity = 1.0f;
|
||||
|
||||
/**
|
||||
* Number of chunks to check
|
||||
*/
|
||||
int chunkRadius = 2;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The list of all chunks with foliage, currently
|
||||
*/
|
||||
List<FoliageChunk> chunks = null;
|
||||
|
||||
/**
|
||||
* Cache used to transfer still-valid chunks to the next frame
|
||||
*/
|
||||
List<FoliageChunk> chunkUpdateCache = null;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starts up the foliage manager
|
||||
*/
|
||||
public void start(){
|
||||
FoliageCell.init();
|
||||
chunks = new LinkedList<FoliageChunk>();
|
||||
chunkUpdateCache = new LinkedList<FoliageChunk>();
|
||||
ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all grass entities
|
||||
*/
|
||||
public void update(){
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update");
|
||||
if(ready && Globals.userSettings.getGraphicsPerformanceEnableFoliageManager() && this.dependenciesAreReady()){
|
||||
this.flipUpdateCache();
|
||||
for(int x = -chunkRadius; x < chunkRadius+1; x++){
|
||||
for(int y = -chunkRadius; y < chunkRadius+1; y++){
|
||||
for(int z = -chunkRadius; z < chunkRadius+1; z++){
|
||||
Vector3i worldPos = Globals.clientWorldData.convertRealToWorldSpace(EntityUtils.getPosition(Globals.playerEntity)).add(x,y,z);
|
||||
if(Globals.clientWorldData.worldPosInBounds(worldPos)){
|
||||
this.updatePosition(worldPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update - destroy chunks");
|
||||
for(FoliageChunk chunk : this.chunkUpdateCache){
|
||||
chunk.destroy();
|
||||
}
|
||||
this.chunkUpdateCache.clear();
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a position in the world
|
||||
* @param worldPos The world position
|
||||
*/
|
||||
private void updatePosition(Vector3i worldPos){
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.updatePosition");
|
||||
FoliageChunk foundChunk = null;
|
||||
for(FoliageChunk chunk : chunkUpdateCache){
|
||||
if(chunk.getWorldPos().equals(worldPos)){
|
||||
this.chunks.add(chunk);
|
||||
foundChunk = chunk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(foundChunk == null){
|
||||
foundChunk = new FoliageChunk(worldPos);
|
||||
this.chunks.add(foundChunk);
|
||||
foundChunk.initCells();
|
||||
} else {
|
||||
chunkUpdateCache.remove(foundChunk);
|
||||
}
|
||||
foundChunk.updateCells();
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips references for the chunk list and chunk update cache
|
||||
*/
|
||||
private void flipUpdateCache(){
|
||||
List<FoliageChunk> list1 = this.chunks;
|
||||
this.chunks = this.chunkUpdateCache;
|
||||
this.chunkUpdateCache = list1;
|
||||
if(this.chunks.size() > 0){
|
||||
throw new IllegalStateException("Update cache should have be empty and it isn't!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a key for a foliage cell in the localCellMap
|
||||
* @param worldPosition The world position of the cell
|
||||
* @param voxelPosition The voxel position of the cell
|
||||
* @return The key for the cell
|
||||
*/
|
||||
protected static String getFoliageCellKey(Vector3i worldPosition, Vector3i voxelPosition){
|
||||
return worldPosition.x + "_" + worldPosition.y + "_" + worldPosition.z + "_" + voxelPosition.x + "_" + voxelPosition.y + "_" + voxelPosition.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all dependencies of this manager are ready
|
||||
* @return true if all are ready, false otherwise
|
||||
*/
|
||||
public boolean dependenciesAreReady(){
|
||||
return
|
||||
Globals.clientWorldData != null &&
|
||||
Globals.clientDrawCellManager != null &&
|
||||
Globals.playerEntity != null
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the foliage chunk at the position
|
||||
* @param worldPos The position
|
||||
*/
|
||||
public void evaluateChunk(Vector3i worldPos){
|
||||
for(FoliageChunk chunk : chunkUpdateCache){
|
||||
if(chunk.getWorldPos().equals(worldPos)){
|
||||
chunk.updateCells();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all foliage in the foliage manager
|
||||
*/
|
||||
public void draw(){
|
||||
for(FoliageChunk chunk : chunks){
|
||||
chunk.draw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,602 +0,0 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joml.Matrix4d;
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Sphered;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import electrosphere.client.entity.camera.CameraEntityUtils;
|
||||
import electrosphere.client.terrain.cache.ChunkData;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.ClientEntityUtils;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityCreationUtils;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.state.foliage.AmbientFoliage;
|
||||
import electrosphere.game.data.foliage.type.FoliageType;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.renderer.OpenGLState;
|
||||
import electrosphere.renderer.RenderPipelineState;
|
||||
import electrosphere.renderer.actor.instance.TextureInstancedActor;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
import electrosphere.renderer.texture.Texture;
|
||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||
|
||||
@Deprecated
|
||||
/**
|
||||
* Contains a set of foliage entities and groups them together.
|
||||
*/
|
||||
public class FoliageCell {
|
||||
|
||||
/**
|
||||
* the interval to space along
|
||||
*/
|
||||
static final int TARGET_FOLIAGE_SPACING = 50;
|
||||
|
||||
/**
|
||||
* The target number of foliage to place per cell
|
||||
*/
|
||||
static final int TARGET_FOLIAGE_PER_CELL = TARGET_FOLIAGE_SPACING * TARGET_FOLIAGE_SPACING;
|
||||
|
||||
/**
|
||||
* the length of the ray to ground test with
|
||||
*/
|
||||
static final float RAY_LENGTH = 1.0f;
|
||||
|
||||
/**
|
||||
* the height above the chunk to start from when sampling downwards
|
||||
*/
|
||||
static final float SAMPLE_START_HEIGHT = 0.5f;
|
||||
|
||||
/**
|
||||
* The ID of the air voxel
|
||||
*/
|
||||
static final int AIR_VOXEL_ID = 0;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Size of a single item of foliage in the texture buffer
|
||||
* </p>
|
||||
* A lot of these are x 4 to account for size of float
|
||||
* 3 x 4 for position
|
||||
* 2 x 4 for euler rotation
|
||||
*
|
||||
*
|
||||
* eventually:
|
||||
* grass type
|
||||
* color
|
||||
* wind characteristics?
|
||||
*/
|
||||
static final int SINGLE_FOLIAGE_DATA_SIZE_BYTES = 3 * 4 + 2 * 4;
|
||||
|
||||
/**
|
||||
* The map of all attributes for instanced foliage
|
||||
*/
|
||||
static final Map<ShaderAttribute,HomogenousBufferTypes> attributes = new HashMap<ShaderAttribute,HomogenousBufferTypes>();
|
||||
|
||||
/**
|
||||
* model matrix shader attribute
|
||||
*/
|
||||
static ShaderAttribute modelMatrixAttribute;
|
||||
|
||||
/**
|
||||
* The list of voxel type ids that should have grass generated on top of them
|
||||
*/
|
||||
static final List<Integer> grassGeneratingVoxelIds = new ArrayList<Integer>();
|
||||
|
||||
//set attributes
|
||||
static {
|
||||
int[] attributeIndices = new int[]{
|
||||
5,6,7,8
|
||||
};
|
||||
modelMatrixAttribute = new ShaderAttribute(attributeIndices);
|
||||
attributes.put(modelMatrixAttribute,HomogenousBufferTypes.MAT4F);
|
||||
|
||||
//set grass generating voxel ids
|
||||
grassGeneratingVoxelIds.add(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertex shader path
|
||||
*/
|
||||
static final String vertexPath = "Shaders/entities/foliage/foliage.vs";
|
||||
|
||||
/**
|
||||
* fragment shader path
|
||||
*/
|
||||
static final String fragmentPath = "Shaders/entities/foliage/foliage.fs";
|
||||
|
||||
/**
|
||||
* Random for finding new positions for foliage
|
||||
*/
|
||||
Random placementRandomizer = new Random();
|
||||
|
||||
/**
|
||||
* The scale of the chunk
|
||||
*/
|
||||
int scale;
|
||||
|
||||
/**
|
||||
* Position of the foliage cell in world coordinates
|
||||
*/
|
||||
protected Vector3i worldPosition;
|
||||
|
||||
/**
|
||||
* Position of the foliage cell in local coordinates
|
||||
*/
|
||||
protected Vector3i voxelPosition;
|
||||
|
||||
/**
|
||||
* The real position of this cell, stored so we don't constantly have to recalculate
|
||||
*/
|
||||
protected Vector3d realPosition;
|
||||
|
||||
/**
|
||||
* Constituent entities
|
||||
*/
|
||||
protected Set<Entity> containedEntities;
|
||||
|
||||
/**
|
||||
* Template bounding shere used for checking frustum for this cell
|
||||
*/
|
||||
static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,2);
|
||||
|
||||
/**
|
||||
* Tracks whether the cell has generated or not
|
||||
*/
|
||||
boolean hasGenerated = false;
|
||||
|
||||
/**
|
||||
* Tracks whether this cell should be evaluated or not
|
||||
*/
|
||||
boolean shouldEvaluate = true;
|
||||
|
||||
/**
|
||||
* Inits the foliage cell data
|
||||
*/
|
||||
static void init(){
|
||||
//queue ambient foliage models
|
||||
for(FoliageType foliageType : Globals.gameConfigCurrent.getFoliageMap().getFoliageList()){
|
||||
if(foliageType.getTokens().contains(FoliageType.TOKEN_AMBIENT)){
|
||||
Globals.assetManager.addModelPathToQueue(foliageType.getGraphicsTemplate().getModel().getPath());
|
||||
Globals.assetManager.addShaderToQueue(vertexPath, fragmentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param worldPos The position of the foliage cell in world coordinates
|
||||
* @param voxelPos The position of the foliage cell in voxel coordinates
|
||||
*/
|
||||
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos, int scale){
|
||||
this.worldPosition = worldPos;
|
||||
this.voxelPosition = voxelPos;
|
||||
this.realPosition = realPos;
|
||||
this.scale = scale;
|
||||
this.containedEntities = new HashSet<Entity>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entity to this foliage cell
|
||||
* @param entity The entity to add
|
||||
*/
|
||||
protected void addEntity(Entity entity){
|
||||
containedEntities.add(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all entities in this foliage cell
|
||||
*/
|
||||
protected void clearEntities(){
|
||||
containedEntities.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys all entities in this foliage cell
|
||||
*/
|
||||
protected void destroy(){
|
||||
for(Entity entity : containedEntities){
|
||||
ClientEntityUtils.destroyEntity(entity);
|
||||
}
|
||||
clearEntities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the foliage cell
|
||||
*/
|
||||
protected void generate(){
|
||||
boolean shouldGenerate = false;
|
||||
if(voxelPosition.y + 1 >= ServerTerrainChunk.CHUNK_DIMENSION){
|
||||
return;
|
||||
}
|
||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosition,ChunkData.NO_STRIDE);
|
||||
if(data == null){
|
||||
return;
|
||||
}
|
||||
if(!Globals.clientDrawCellManager.isFullLOD(worldPosition)){
|
||||
return;
|
||||
}
|
||||
//get foliage types supported
|
||||
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
||||
boolean airAbove = data.getType(voxelPosition.x,voxelPosition.y+1,voxelPosition.z) == 0;
|
||||
if(foliageTypesSupported != null && foliageTypesSupported.size() > 0 && airAbove && scale < 3){
|
||||
shouldGenerate = true;
|
||||
}
|
||||
if(shouldGenerate){
|
||||
//get type
|
||||
String foliageTypeName = foliageTypesSupported.get(placementRandomizer.nextInt() % foliageTypesSupported.size());
|
||||
FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(foliageTypeName);
|
||||
|
||||
//create cell and buffer
|
||||
ByteBuffer buffer = BufferUtils.createByteBuffer(TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
if(buffer.capacity() < TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES){
|
||||
LoggerInterface.loggerEngine.WARNING("Failed to allocate data for foliage cell! " + buffer.limit());
|
||||
}
|
||||
FloatBuffer floatBufferView = buffer.asFloatBuffer();
|
||||
int drawCount = 0;
|
||||
for(int x = 0; x < scale; x++){
|
||||
for(int y = 0; y < scale; y++){
|
||||
for(int z = 0; z < scale; z++){
|
||||
drawCount = drawCount + this.insertBlades(x, y, z, floatBufferView, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// drawCount = drawCount + this.insertBlades(0, 0, 0, floatBufferView, data);
|
||||
if(drawCount > 0){
|
||||
buffer.position(0);
|
||||
buffer.limit(TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
//construct data texture
|
||||
Texture dataTexture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4,TARGET_FOLIAGE_PER_CELL);
|
||||
|
||||
//create entity
|
||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||
|
||||
TextureInstancedActor.attachTextureInstancedActor(grassEntity, foliageType.getGraphicsTemplate().getModel().getPath(), vertexPath, fragmentPath, dataTexture, drawCount);
|
||||
EntityUtils.getPosition(grassEntity).set(realPosition);
|
||||
EntityUtils.getRotation(grassEntity).set(0,0,0,1);
|
||||
EntityUtils.getScale(grassEntity).set(1,1,1);
|
||||
//add ambient foliage behavior tree
|
||||
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate());
|
||||
this.addEntity(grassEntity);
|
||||
}
|
||||
}
|
||||
this.shouldEvaluate = false;
|
||||
this.hasGenerated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert blades of grass into the entity
|
||||
* @param vX the x offset of the voxel
|
||||
* @param vY the y offset of the voxel
|
||||
* @param vZ the z offset of the voxel
|
||||
* @param floatBufferView the gpu data buffer
|
||||
* @param chunkData the chunk data
|
||||
* @return the number of blades of grass added
|
||||
*/
|
||||
protected int insertBlades(int vX, int vY, int vZ, FloatBuffer floatBufferView, ChunkData chunkData){
|
||||
int rVal = 0;
|
||||
|
||||
//get positions offset
|
||||
Vector3d voxelRealPos = new Vector3d(realPosition).add(vX,vY,vZ);
|
||||
Vector3i currVoxelPos = new Vector3i(voxelPosition).add(vY,vY,vZ);
|
||||
|
||||
//check that the current voxel even supports foliage
|
||||
boolean shouldGenerate = false;
|
||||
List<String> foliageTypesSupported = null;
|
||||
if(chunkData != null && currVoxelPos.y + 1 < ServerTerrainChunk.CHUNK_DIMENSION){
|
||||
foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(chunkData.getType(currVoxelPos)).getAmbientFoliage();
|
||||
boolean airAbove = chunkData.getType(currVoxelPos.x,currVoxelPos.y+1,currVoxelPos.z) == AIR_VOXEL_ID;
|
||||
if(foliageTypesSupported != null && airAbove){
|
||||
shouldGenerate = true;
|
||||
}
|
||||
}
|
||||
if(shouldGenerate){
|
||||
//construct simple grid to place foliage on
|
||||
Vector3d sample_00 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_01 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_02 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_10 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_11 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_12 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_20 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_21 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_22 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
//get the heights of each sample
|
||||
float height_11 = (float)(sample_11 != null ? sample_11.y : 0);
|
||||
float height_00 = (float)(sample_00 != null ? sample_00.y : height_11);
|
||||
float height_01 = (float)(sample_01 != null ? sample_01.y : height_11);
|
||||
float height_02 = (float)(sample_02 != null ? sample_02.y : height_11);
|
||||
float height_10 = (float)(sample_10 != null ? sample_10.y : height_11);
|
||||
float height_12 = (float)(sample_12 != null ? sample_12.y : height_11);
|
||||
float height_20 = (float)(sample_20 != null ? sample_20.y : height_11);
|
||||
float height_21 = (float)(sample_21 != null ? sample_21.y : height_11);
|
||||
float height_22 = (float)(sample_22 != null ? sample_22.y : height_11);
|
||||
//each height is in real world coordinates that are absolute
|
||||
//when rendering, there's already a y offset for the center of the field of grass (based on the model matrix)
|
||||
//so when offseting the position of the blade of grass RELATIVE to the overall instance being drawn, need to subtract the real world coordinates of the overall instance
|
||||
//in other words realPos SPECIFICALLY for the y dimension, for x and z you don't need to worry about it
|
||||
|
||||
//if we don't find data for the center sample, can't place grass so don't create entity
|
||||
if(sample_11 != null){
|
||||
//generate positions to place
|
||||
for(int x = 0; x < TARGET_FOLIAGE_SPACING; x=x+scale){
|
||||
for(int z = 0; z < TARGET_FOLIAGE_SPACING; z=z+scale){
|
||||
//get position to place
|
||||
double rand1 = placementRandomizer.nextDouble();
|
||||
double rand2 = placementRandomizer.nextDouble();
|
||||
double relativePositionOnGridX = x / (1.0 * TARGET_FOLIAGE_SPACING) + rand1 / TARGET_FOLIAGE_SPACING;
|
||||
double relativePositionOnGridZ = z / (1.0 * TARGET_FOLIAGE_SPACING) + rand2 / TARGET_FOLIAGE_SPACING;
|
||||
double offsetX = relativePositionOnGridX - 0.5;
|
||||
double offsetZ = relativePositionOnGridZ - 0.5;
|
||||
//determine quadrant we're placing in
|
||||
double offsetY = 0;
|
||||
boolean addBlade = false;
|
||||
if(relativePositionOnGridX >=0.5){
|
||||
if(relativePositionOnGridZ >= 0.5){
|
||||
relativePositionOnGridX = relativePositionOnGridX - 0.5;
|
||||
relativePositionOnGridZ = relativePositionOnGridZ - 0.5;
|
||||
relativePositionOnGridX /= 0.5;
|
||||
relativePositionOnGridZ /= 0.5;
|
||||
// System.out.println(relativePositionOnGridX + " " + relativePositionOnGridZ);
|
||||
//if we have heights for all four surrounding spots, interpolate for y value
|
||||
if(sample_11 != null && sample_12 != null && sample_21 != null && sample_22 != null){
|
||||
offsetY =
|
||||
height_11 * (1-relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_12 * (1-relativePositionOnGridX) * ( relativePositionOnGridZ) +
|
||||
height_21 * ( relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_22 * ( relativePositionOnGridX) * ( relativePositionOnGridZ);
|
||||
addBlade = true;
|
||||
}
|
||||
} else {
|
||||
relativePositionOnGridX = relativePositionOnGridX - 0.5;
|
||||
relativePositionOnGridX /= 0.5;
|
||||
relativePositionOnGridZ /= 0.5;
|
||||
//if we have heights for all four surrounding spots, interpolate for y value
|
||||
if(sample_10 != null && sample_11 != null && sample_20 != null && sample_21 != null){
|
||||
offsetY =
|
||||
height_10 * (1-relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_11 * (1-relativePositionOnGridX) * ( relativePositionOnGridZ) +
|
||||
height_20 * ( relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_21 * ( relativePositionOnGridX) * ( relativePositionOnGridZ);
|
||||
addBlade = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(relativePositionOnGridZ >= 0.5){
|
||||
relativePositionOnGridZ = relativePositionOnGridZ - 0.5;
|
||||
relativePositionOnGridX /= 0.5;
|
||||
relativePositionOnGridZ /= 0.5;
|
||||
//if we have heights for all four surrounding spots, interpolate for y value
|
||||
if(sample_01 != null && sample_02 != null && sample_11 != null && sample_12 != null){
|
||||
offsetY =
|
||||
height_01 * (1-relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_02 * (1-relativePositionOnGridX) * ( relativePositionOnGridZ) +
|
||||
height_11 * ( relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_12 * ( relativePositionOnGridX) * ( relativePositionOnGridZ);
|
||||
addBlade = true;
|
||||
}
|
||||
} else {
|
||||
relativePositionOnGridX /= 0.5;
|
||||
relativePositionOnGridZ /= 0.5;
|
||||
//if we have heights for all four surrounding spots, interpolate for y value
|
||||
if(sample_00 != null && sample_01 != null && sample_10 != null && sample_11 != null){
|
||||
offsetY =
|
||||
height_00 * (1-relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_01 * (1-relativePositionOnGridX) * ( relativePositionOnGridZ) +
|
||||
height_10 * ( relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
||||
height_11 * ( relativePositionOnGridX) * ( relativePositionOnGridZ);
|
||||
addBlade = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(addBlade){
|
||||
//convert y to relative to chunk
|
||||
offsetY = offsetY - realPosition.y;
|
||||
double rotVar = placementRandomizer.nextDouble() * Math.PI * 2;
|
||||
double rotVar2 = placementRandomizer.nextDouble();
|
||||
if(floatBufferView.limit() >= floatBufferView.position() + 4){
|
||||
floatBufferView.put((float)offsetX + vX);
|
||||
floatBufferView.put((float)offsetY + vY);
|
||||
floatBufferView.put((float)offsetZ + vZ);
|
||||
floatBufferView.put((float)rotVar);
|
||||
floatBufferView.put((float)rotVar2);
|
||||
rVal++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a good position to put a new blade of grass
|
||||
* @param centerPosition The player's position
|
||||
* @return The new position for the blade of grass
|
||||
*/
|
||||
protected Vector3d getNewPosition(Vector3d centerPosition){
|
||||
double angle = placementRandomizer.nextDouble() * Math.PI * 2;
|
||||
double radius = placementRandomizer.nextDouble();
|
||||
return new Vector3d(
|
||||
centerPosition.x + Math.cos(angle) * radius,
|
||||
centerPosition.y,
|
||||
centerPosition.z + Math.sin(angle) * radius
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new rotation for a blade of grass
|
||||
* @return The rotation
|
||||
*/
|
||||
protected Quaterniond getNewRotation(){
|
||||
return new Quaterniond().rotationX(-Math.PI / 2.0f).rotateLocalY(Math.PI * placementRandomizer.nextFloat()).normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all entities in the foliage cell
|
||||
*/
|
||||
protected void draw(){
|
||||
if(this.containedEntities.size() > 0){
|
||||
Matrix4d modelMatrix = new Matrix4d();
|
||||
Vector3d cameraCenter = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
|
||||
|
||||
RenderPipelineState renderPipelineState = Globals.renderingEngine.getRenderPipelineState();
|
||||
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||
|
||||
Vector3d cameraModifiedPosition = new Vector3d(realPosition).sub(cameraCenter);
|
||||
//frustum check entire cell
|
||||
boolean shouldRender = renderPipelineState.getFrustumIntersection().testSphere((float)(cameraModifiedPosition.x + boundingSphere.x), (float)(cameraModifiedPosition.y + boundingSphere.y), (float)(cameraModifiedPosition.z + boundingSphere.z), (float)(boundingSphere.r));
|
||||
if(shouldRender){
|
||||
//disable frustum check and instead perform at cell level
|
||||
boolean currentFrustumCheckState = renderPipelineState.shouldFrustumCheck();
|
||||
renderPipelineState.setFrustumCheck(false);
|
||||
for(Entity entity : containedEntities){
|
||||
Vector3d grassPosition = EntityUtils.getPosition(entity);
|
||||
Quaterniond grassRotation = EntityUtils.getRotation(entity);
|
||||
TextureInstancedActor actor = TextureInstancedActor.getTextureInstancedActor(entity);
|
||||
|
||||
|
||||
modelMatrix = modelMatrix.identity();
|
||||
modelMatrix.translate(cameraModifiedPosition);
|
||||
modelMatrix.rotate(new Quaterniond(grassRotation));
|
||||
modelMatrix.scale(new Vector3d(EntityUtils.getScale(entity)));
|
||||
actor.applySpatialData(modelMatrix,grassPosition);
|
||||
|
||||
|
||||
//draw
|
||||
actor.draw(renderPipelineState, openGLState);
|
||||
}
|
||||
renderPipelineState.setFrustumCheck(currentFrustumCheckState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the cell has generated or not
|
||||
* @return true if has generated, false otherwise
|
||||
*/
|
||||
public boolean hasGenerated(){
|
||||
return this.hasGenerated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cell should be continuously evaluated
|
||||
* @return true if should be evaluated, false otherwise
|
||||
*/
|
||||
public boolean shouldEvaluate() {
|
||||
return shouldEvaluate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the cell should be continuously evaluated
|
||||
* @param shouldEvaluate true if should be evaluated, false otherwise
|
||||
*/
|
||||
public void setShouldEvaluate(boolean shouldEvaluate) {
|
||||
this.shouldEvaluate = shouldEvaluate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SCAFFOLDING FOR BUILDING SCALE>1 CELLS AND ALSO FOR TOP LEVEL CELL CHECKING
|
||||
*/
|
||||
/**
|
||||
* Evaluates a chunk to see where foliage cells should be created or updated
|
||||
* @param worldPos The world position of the chunk
|
||||
*/
|
||||
// public void evaluateChunk(Vector3i worldPos){
|
||||
// ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||
// for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
||||
// //can't go to very top 'cause otherwise there would be no room to put grass
|
||||
// for(int y = 0; y < ChunkData.CHUNK_SIZE - 1; y++){
|
||||
// for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
||||
// Vector3i currentPos = new Vector3i(x,y,z);
|
||||
// String key = getFoliageCellKey(worldPos, currentPos);
|
||||
// if(locationCellMap.get(key) != null){
|
||||
// //destroy if there's no longer ground or
|
||||
// //if the cell above is now occupied or
|
||||
// //if the lower cell is no longer supporting foliage
|
||||
// if(
|
||||
// data.getWeight(currentPos) <= 0 ||
|
||||
// data.getWeight(new Vector3i(x,y + 1,z)) > 0 ||
|
||||
// !typeSupportsFoliage(data.getType(currentPos))
|
||||
// ){
|
||||
// //destroy
|
||||
// FoliageCell toDestroy = locationCellMap.get(key);
|
||||
// toDestroy.destroy();
|
||||
// activeCells.remove(toDestroy);
|
||||
// locationCellMap.remove(key);
|
||||
// } else {
|
||||
// //TODO: evaluate if foliage is placed well
|
||||
// }
|
||||
// } else {
|
||||
// //create if current is ground and above is air
|
||||
// if(
|
||||
// !locationEvaluationCooldownMap.containsKey(key) &&
|
||||
// data.getWeight(currentPos) > 0 &&
|
||||
// data.getWeight(new Vector3i(x,y + 1,z)) < 0 &&
|
||||
// typeSupportsFoliage(data.getType(currentPos)) &&
|
||||
// activeCells.size() < CELL_COUNT_MAX
|
||||
// ){
|
||||
// //create foliage cell
|
||||
// createFoliageCell(worldPos,currentPos,1,targetDensity);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// //evaluate top cells if chunk above this one exists
|
||||
// ChunkData aboveData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0));
|
||||
// if(aboveData != null){
|
||||
// for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
||||
// for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
||||
// Vector3i currentPos = new Vector3i(x,ChunkData.CHUNK_SIZE-1,z);
|
||||
// String key = getFoliageCellKey(worldPos, currentPos);
|
||||
// if(locationCellMap.get(key) != null){
|
||||
// //destroy if there's no longer ground or
|
||||
// //if the cell above is now occupied or
|
||||
// //if the lower cell is no longer supporting foliage
|
||||
// if(
|
||||
// data.getWeight(currentPos) <= 0 ||
|
||||
// aboveData.getWeight(new Vector3i(x,0,z)) > 0 ||
|
||||
// !typeSupportsFoliage(data.getType(currentPos))
|
||||
// ){
|
||||
// //destroy
|
||||
// FoliageCell toDestroy = locationCellMap.get(key);
|
||||
// toDestroy.destroy();
|
||||
// activeCells.remove(toDestroy);
|
||||
// locationCellMap.remove(key);
|
||||
// } else {
|
||||
// //TODO: evaluate if foliage is placed well
|
||||
// }
|
||||
// } else {
|
||||
// //create if current is ground and above is air
|
||||
// if(
|
||||
// data.getWeight(currentPos) > 0 &&
|
||||
// aboveData.getWeight(new Vector3i(x,0,z)) < 0 &&
|
||||
// typeSupportsFoliage(data.getType(currentPos)) &&
|
||||
// activeCells.size() < CELL_COUNT_MAX
|
||||
// ){
|
||||
// //create foliage cell
|
||||
// createFoliageCell(worldPos,currentPos,1,targetDensity);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@ -1,358 +0,0 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.client.terrain.cache.ChunkData;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.util.ds.octree.ChunkTree;
|
||||
import electrosphere.util.ds.octree.ChunkTree.ChunkTreeNode;
|
||||
import electrosphere.util.math.GeomUtils;
|
||||
|
||||
@Deprecated
|
||||
/**
|
||||
* A whole chunk of foliage
|
||||
*/
|
||||
public class FoliageChunk {
|
||||
|
||||
/**
|
||||
* The world position of this chunk
|
||||
*/
|
||||
Vector3i worldPos;
|
||||
Vector3d realPos;
|
||||
|
||||
/**
|
||||
* The distance to draw at full resolution
|
||||
*/
|
||||
static final double FULL_RES_DIST = 15;
|
||||
|
||||
/**
|
||||
* The distance for half resolution
|
||||
*/
|
||||
static final double HALF_RES_DIST = 30;
|
||||
|
||||
/**
|
||||
* Tracks whether this chunk contains a foliage voxel or not
|
||||
*/
|
||||
boolean containsFoliageVoxel = false;
|
||||
|
||||
/**
|
||||
* Tracks whether this foliage chunk has properly initialized or not.
|
||||
* It is only considered initialized once it has been evaluated with the data present in cache.
|
||||
*/
|
||||
boolean initialized = false;
|
||||
|
||||
/**
|
||||
* The octree holding all the chunks to evaluate
|
||||
*/
|
||||
ChunkTree<FoliageCell> chunkTree;
|
||||
|
||||
/**
|
||||
* Data for the current chunk
|
||||
*/
|
||||
ChunkData currentChunkData;
|
||||
|
||||
/**
|
||||
* Data for the above chunk
|
||||
*/
|
||||
ChunkData aboveChunkData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param worldPos The world position of the chunk
|
||||
*/
|
||||
public FoliageChunk(Vector3i worldPos){
|
||||
this.worldPos = worldPos;
|
||||
this.realPos = Globals.clientWorldData.convertWorldToRealSpace(worldPos);
|
||||
this.chunkTree = new ChunkTree<FoliageCell>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world position of the chunk
|
||||
* @return The world position of the chunk
|
||||
*/
|
||||
public Vector3i getWorldPos(){
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all cells in the chunk
|
||||
*/
|
||||
public void initCells(){
|
||||
Globals.profiler.beginCpuSample("FoliageChunk.initCells");
|
||||
this.currentChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos,ChunkData.NO_STRIDE);
|
||||
// //evaluate top cells if chunk above this one exists
|
||||
this.aboveChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0),ChunkData.NO_STRIDE);
|
||||
this.updateCells();
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all cells in the chunk
|
||||
*/
|
||||
public void updateCells(){
|
||||
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
||||
//re-evaluate whether contains foliage voxel or not
|
||||
boolean hasData = Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE);
|
||||
boolean hasPhysics = Globals.clientDrawCellManager.hasGeneratedPhysics(worldPos.x, worldPos.y, worldPos.z);
|
||||
if(containsFoliageVoxel && hasData && hasPhysics){
|
||||
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||
//the sets to iterate through
|
||||
boolean updated = true;
|
||||
int attempts = 0;
|
||||
while(updated && attempts < 3){
|
||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||
updated = this.recursivelyUpdateCells(rootNode, playerPos);
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
if(!hasData){
|
||||
Globals.clientTerrainManager.requestChunk(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE);
|
||||
}
|
||||
if(hasData && !this.initialized) {
|
||||
this.evaluateContainsFoliage();
|
||||
this.initialized = true;
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the chunk contains a foliage voxel or not
|
||||
* @return true if contains foliage voxel, false otherwise
|
||||
*/
|
||||
private boolean checkContainsFoliageVoxel(){
|
||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(this.getWorldPos(),ChunkData.NO_STRIDE);
|
||||
if(data == null){
|
||||
return false;
|
||||
}
|
||||
for(int x = 0; x < ChunkData.CHUNK_DATA_SIZE; x++){
|
||||
for(int y = 0; y < ChunkData.CHUNK_DATA_SIZE; y++){
|
||||
for(int z = 0; z < ChunkData.CHUNK_DATA_SIZE; z++){
|
||||
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(new Vector3i(x,y,z))).getAmbientFoliage();
|
||||
if(foliageTypesSupported != null && foliageTypesSupported.size() > 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the chunk to evaluate whether it has foliage or not
|
||||
*/
|
||||
public void evaluateContainsFoliage(){
|
||||
this.containsFoliageVoxel = this.checkContainsFoliageVoxel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively update child nodes
|
||||
* @param node The root node
|
||||
* @param playerPos The player's position
|
||||
*/
|
||||
private boolean recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
||||
boolean updated = false;
|
||||
Globals.profiler.beginRecursiveCpuSample("FoliageChunk.recursivelyUpdateCells");
|
||||
if(this.shouldSplit(playerPos, node)){
|
||||
Globals.profiler.beginAggregateCpuSample("FoliageChunk.split");
|
||||
//perform op
|
||||
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
||||
|
||||
//do deletions
|
||||
this.recursivelyDestroy(node);
|
||||
|
||||
//do creations
|
||||
container.getChildren().forEach(child -> {
|
||||
Vector3d realPos = new Vector3d(
|
||||
worldPos.x * ChunkData.CHUNK_DATA_SIZE + child.getMinBound().x,
|
||||
worldPos.y * ChunkData.CHUNK_DATA_SIZE + child.getMinBound().y,
|
||||
worldPos.z * ChunkData.CHUNK_DATA_SIZE + child.getMinBound().z
|
||||
);
|
||||
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel()));
|
||||
});
|
||||
Globals.profiler.endCpuSample();
|
||||
updated = true;
|
||||
} else if(this.shouldJoin(playerPos, node)) {
|
||||
Globals.profiler.beginAggregateCpuSample("FoliageChunk.join");
|
||||
//perform op
|
||||
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
||||
|
||||
//do deletions
|
||||
this.recursivelyDestroy(node);
|
||||
|
||||
//do creations
|
||||
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel()));
|
||||
Globals.profiler.endCpuSample();
|
||||
updated = true;
|
||||
} else if(shouldGenerate(playerPos, node)){
|
||||
Globals.profiler.beginAggregateCpuSample("FoliageChunk.generate");
|
||||
node.getData().generate();
|
||||
Globals.profiler.endCpuSample();
|
||||
updated = true;
|
||||
} else if(!node.isLeaf()){
|
||||
List<ChunkTreeNode<FoliageCell>> children = new LinkedList<ChunkTreeNode<FoliageCell>>(node.getChildren());
|
||||
for(ChunkTreeNode<FoliageCell> child : children){
|
||||
boolean childUpdate = recursivelyUpdateCells(child, playerPos);
|
||||
updated = childUpdate || updated;
|
||||
}
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum distance from a node to a point
|
||||
* @param pos the position to check against
|
||||
* @param node the node
|
||||
* @return the distance
|
||||
*/
|
||||
public double getMinDistance(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
Vector3i min = node.getMinBound();
|
||||
Vector3i max = node.getMaxBound();
|
||||
|
||||
double minX = min.x + realPos.x;
|
||||
double minY = min.y + realPos.y;
|
||||
double minZ = min.z + realPos.z;
|
||||
|
||||
double maxX = max.x + realPos.x;
|
||||
double maxY = max.y + realPos.y;
|
||||
double maxZ = max.z + realPos.z;
|
||||
return GeomUtils.getMinDistanceAABB(pos, new Vector3d(minX,minY,minZ), new Vector3d(maxX,maxY,maxZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this should be split or not
|
||||
* @param pos the player position
|
||||
* @param node The node
|
||||
* @return true if should split, false otherwise
|
||||
*/
|
||||
public boolean shouldSplit(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
//breaking out into dedicated function so can add case handling ie if we want
|
||||
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||
return
|
||||
node.isLeaf() &&
|
||||
node.canSplit() &&
|
||||
(
|
||||
(
|
||||
node.getLevel() < ChunkTree.MAX_LEVEL - 1 &&
|
||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
node.getLevel() < ChunkTree.MAX_LEVEL &&
|
||||
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this should be joined or not
|
||||
* @param pos the player position
|
||||
* @param node The node
|
||||
* @return true if should be joined, false otherwise
|
||||
*/
|
||||
public boolean shouldJoin(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
//breaking out into dedicated function so can add case handling ie if we want
|
||||
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||
return
|
||||
node.getLevel() > 0 &&
|
||||
!node.isLeaf() &&
|
||||
(
|
||||
(
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL &&
|
||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
this.getMinDistance(pos, node) > HALF_RES_DIST
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this cell should generate
|
||||
* @param pos the player's position
|
||||
* @param node the node
|
||||
* @return true if should generate, false otherwise
|
||||
*/
|
||||
public boolean shouldGenerate(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
return
|
||||
node.isLeaf() &&
|
||||
node.getData() != null &&
|
||||
!node.getData().hasGenerated() &&
|
||||
(
|
||||
(
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL
|
||||
// &&
|
||||
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL - 1
|
||||
&&
|
||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node should have destroy called on it
|
||||
* @param node The node
|
||||
* @return true if should destroy, false otherwise
|
||||
*/
|
||||
public boolean shouldDestroy(ChunkTreeNode<FoliageCell> node){
|
||||
return
|
||||
node.getData() != null &&
|
||||
node.getData().containedEntities.size() > 0
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the foliage chunk
|
||||
*/
|
||||
protected void destroy(){
|
||||
this.recursivelyDestroy(this.chunkTree.getRoot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively destroy a tree
|
||||
* @param node The root of the tree
|
||||
*/
|
||||
private void recursivelyDestroy(ChunkTreeNode<FoliageCell> node){
|
||||
if(node.getChildren().size() > 0){
|
||||
node.getChildren().forEach(child -> recursivelyDestroy(child));
|
||||
}
|
||||
if(node.getData() != null){
|
||||
node.getData().destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all cells in the chunk
|
||||
*/
|
||||
protected void draw(){
|
||||
recursivelyDraw(this.chunkTree.getRoot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively draws all nodes
|
||||
* @param node The root node
|
||||
*/
|
||||
private void recursivelyDraw(ChunkTreeNode<FoliageCell> node){
|
||||
if(node.getChildren().size() > 0){
|
||||
node.getChildren().forEach(child -> recursivelyDraw(child));
|
||||
}
|
||||
if(node.getData() != null){
|
||||
node.getData().draw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user