Foliage cell concept
This commit is contained in:
parent
3948f1f921
commit
058c6ac3d9
@ -21,9 +21,15 @@
|
|||||||
{
|
{
|
||||||
"name" : "Green Grass",
|
"name" : "Green Grass",
|
||||||
"tokens" : [
|
"tokens" : [
|
||||||
"AMBIENT"
|
"AMBIENT",
|
||||||
|
"REACTS_TO_WIND",
|
||||||
|
"GROWS_BACK",
|
||||||
|
"FLAMMABLE"
|
||||||
],
|
],
|
||||||
"modelPath" : "Models/falloak1.fbx"
|
"growthModel": {
|
||||||
|
"growthRate" : 0.001
|
||||||
|
},
|
||||||
|
"modelPath" : "Models/grass1.fbx"
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
"id" : 2,
|
"id" : 2,
|
||||||
"name" : "grass",
|
"name" : "grass",
|
||||||
"ambientFoliage" : [
|
"ambientFoliage" : [
|
||||||
"Grass"
|
"Green Grass"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -7,9 +7,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.joml.Matrix4d;
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Quaterniond;
|
import org.joml.Quaterniond;
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
@ -22,8 +21,8 @@ import electrosphere.entity.EntityCreationUtils;
|
|||||||
import electrosphere.entity.EntityDataStrings;
|
import electrosphere.entity.EntityDataStrings;
|
||||||
import electrosphere.entity.EntityTags;
|
import electrosphere.entity.EntityTags;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.entity.types.camera.CameraEntityUtils;
|
import electrosphere.entity.state.foliage.AmbientFoliage;
|
||||||
import electrosphere.renderer.actor.instance.InstancedActor;
|
import electrosphere.game.data.foliage.type.FoliageType;
|
||||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||||
|
|
||||||
@ -40,9 +39,6 @@ public class ClientFoliageManager {
|
|||||||
|
|
||||||
//Random for finding new positions for foliage
|
//Random for finding new positions for foliage
|
||||||
Random placementRandomizer = new Random();
|
Random placementRandomizer = new Random();
|
||||||
|
|
||||||
//The list of grass entities currently in use
|
|
||||||
Set<Entity> grassEntities = new HashSet<Entity>();
|
|
||||||
|
|
||||||
//Used to prevent concurrent usage of grassEntities set
|
//Used to prevent concurrent usage of grassEntities set
|
||||||
boolean ready = false;
|
boolean ready = false;
|
||||||
@ -58,6 +54,13 @@ public class ClientFoliageManager {
|
|||||||
static final float CELL_DISTANCE_MAX = 25f;
|
static final float CELL_DISTANCE_MAX = 25f;
|
||||||
//The maximum number of foliage cells
|
//The maximum number of foliage cells
|
||||||
static final int CELL_COUNT_MAX = 100;
|
static final int CELL_COUNT_MAX = 100;
|
||||||
|
//The target number of foliage to place per cell
|
||||||
|
static final int TARGET_FOLIAGE_PER_CELL = 50;
|
||||||
|
//Stores a list of all locations that are currently invalid which map to
|
||||||
|
//the amount of frames that must pass before they are considered valid to evaluate
|
||||||
|
Map<String,Integer> locationEvaluationCooldownMap = new ConcurrentHashMap<String,Integer>();
|
||||||
|
//The number of frames that must pass before a cell can be reevaluated for foliage placement
|
||||||
|
static final int EVALUATION_COOLDOWN = 100;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -99,24 +102,11 @@ public class ClientFoliageManager {
|
|||||||
* Starts up the foliage manager
|
* Starts up the foliage manager
|
||||||
*/
|
*/
|
||||||
public void start(){
|
public void start(){
|
||||||
//queue grass model
|
//queue ambient foliage models
|
||||||
Globals.assetManager.addModelPathToQueue("models/grass1.fbx");
|
for(FoliageType foliageType : Globals.gameConfigCurrent.getFoliageMap().getFoliageList()){
|
||||||
|
if(foliageType.getTokens().contains(FoliageType.TOKEN_AMBIENT)){
|
||||||
Vector3d centerPosition = new Vector3d(0,0,0);
|
Globals.assetManager.addModelPathToQueue(foliageType.getModelPath());
|
||||||
//create grass entities
|
}
|
||||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
|
||||||
makeEntityInstancedFoliage(grassEntity, "models/grass1.fbx", grassCapacity);
|
|
||||||
EntityUtils.getPosition(grassEntity).set(getNewPosition(centerPosition));
|
|
||||||
EntityUtils.getRotation(grassEntity).set(getNewRotation());
|
|
||||||
EntityUtils.getScale(grassEntity).set(new Vector3d(2.0, 2.0, 2.0));
|
|
||||||
grassEntities.add(grassEntity);
|
|
||||||
for(int i = 0; i < grassCapacity - 1; i++){
|
|
||||||
grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
|
||||||
makeEntityInstancedFoliage(grassEntity, "models/grass1.fbx", grassCapacity);
|
|
||||||
EntityUtils.getPosition(grassEntity).set(getNewPosition(centerPosition));
|
|
||||||
EntityUtils.getRotation(grassEntity).set(getNewRotation());
|
|
||||||
EntityUtils.getScale(grassEntity).set(new Vector3d(2.0, 2.0, 2.0));
|
|
||||||
grassEntities.add(grassEntity);
|
|
||||||
}
|
}
|
||||||
ready = true;
|
ready = true;
|
||||||
}
|
}
|
||||||
@ -126,29 +116,32 @@ public class ClientFoliageManager {
|
|||||||
*/
|
*/
|
||||||
public void update(){
|
public void update(){
|
||||||
if(ready){
|
if(ready){
|
||||||
Matrix4d modelMatrix = new Matrix4d();
|
//TODO: frustum cull at cell level before individual model level
|
||||||
Vector3f cameraCenter = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
|
for(FoliageCell cell : activeCells){
|
||||||
for(Entity grassEntity : grassEntities){
|
cell.draw(modelMatrixAttribute);
|
||||||
Vector3d grassPosition = EntityUtils.getPosition(grassEntity);
|
}
|
||||||
Quaterniond grassRotation = EntityUtils.getRotation(grassEntity);
|
//for each invalid cell, see if can be revalidated
|
||||||
Vector3d playerPosition = EntityUtils.getPosition(Globals.playerEntity);
|
for(String key : locationEvaluationCooldownMap.keySet()){
|
||||||
InstancedActor instancedActor = InstancedActor.getInstancedActor(grassEntity);
|
int cooldownTime = locationEvaluationCooldownMap.get(key);
|
||||||
//update position
|
cooldownTime--;
|
||||||
if(playerPosition.distance(grassPosition) > GRASS_RELOCATION_THRESHOLD){
|
if(cooldownTime <= 0){
|
||||||
grassPosition.set(getNewPosition(playerPosition));
|
String split[] = key.split("_");
|
||||||
grassRotation.set(getNewRotation());
|
Vector3i worldPos = new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2]));
|
||||||
|
Vector3i voxelPos = new Vector3i(Integer.parseInt(split[3]),Integer.parseInt(split[4]),Integer.parseInt(split[5]));
|
||||||
|
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||||
|
//evaluate
|
||||||
|
if(
|
||||||
|
data.getWeight(voxelPos) > 0 &&
|
||||||
|
data.getWeight(new Vector3i(voxelPos.x,voxelPos.y + 1,voxelPos.z)) < 0 &&
|
||||||
|
typeSupportsFoliage(data.getType(voxelPos))
|
||||||
|
){
|
||||||
|
//create foliage cell
|
||||||
|
createFoliageCell(worldPos,voxelPos,0);
|
||||||
|
}
|
||||||
|
locationEvaluationCooldownMap.remove(key);
|
||||||
|
} else {
|
||||||
|
locationEvaluationCooldownMap.put(key, cooldownTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
modelMatrix = modelMatrix.identity();
|
|
||||||
Vector3f cameraModifiedPosition = new Vector3f((float)grassPosition.x,(float)grassPosition.y,(float)grassPosition.z).sub(cameraCenter);
|
|
||||||
modelMatrix.translate(cameraModifiedPosition);
|
|
||||||
modelMatrix.rotate(new Quaterniond(grassRotation));
|
|
||||||
modelMatrix.scale(new Vector3d(EntityUtils.getScale(grassEntity)));
|
|
||||||
|
|
||||||
instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f(modelMatrix));
|
|
||||||
|
|
||||||
//draw
|
|
||||||
// instancedActor.draw(Globals.renderingEngine.getRenderPipelineState());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,6 +184,7 @@ public class ClientFoliageManager {
|
|||||||
* Makes an already created entity a drawable, instanced entity (client only) by backing it with an InstancedActor
|
* Makes an already created entity a drawable, instanced entity (client only) by backing it with an InstancedActor
|
||||||
* @param entity The entity
|
* @param entity The entity
|
||||||
* @param modelPath The model path for the model to back the instanced actor
|
* @param modelPath The model path for the model to back the instanced actor
|
||||||
|
* @param capacity The capacity of the instanced actor to draw
|
||||||
*/
|
*/
|
||||||
public static void makeEntityInstancedFoliage(Entity entity, String modelPath, int capacity){
|
public static void makeEntityInstancedFoliage(Entity entity, String modelPath, int capacity){
|
||||||
entity.putData(EntityDataStrings.INSTANCED_ACTOR, Globals.clientInstanceManager.createInstancedActor(modelPath, vertexPath, fragmentPath, attributes, capacity));
|
entity.putData(EntityDataStrings.INSTANCED_ACTOR, Globals.clientInstanceManager.createInstancedActor(modelPath, vertexPath, fragmentPath, attributes, capacity));
|
||||||
@ -212,26 +206,35 @@ public class ClientFoliageManager {
|
|||||||
//can't go to very top 'cause otherwise there would be no room to put grass
|
//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 y = 0; y < ChunkData.CHUNK_SIZE - 1; y++){
|
||||||
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
||||||
String key = getFoliageCellKey(worldPos, new Vector3i(x,y,z));
|
Vector3i currentPos = new Vector3i(x,y,z);
|
||||||
|
String key = getFoliageCellKey(worldPos, currentPos);
|
||||||
if(locationCellMap.get(key) != null){
|
if(locationCellMap.get(key) != null){
|
||||||
//destroy if there's no longer ground or
|
//destroy if there's no longer ground or
|
||||||
//if the cell above is now occupied or
|
//if the cell above is now occupied or
|
||||||
//if the lower cell is no longer supporting foliage
|
//if the lower cell is no longer supporting foliage
|
||||||
if(data.getWeight(new Vector3i(x,y,z)) <= 0 ||
|
if(
|
||||||
data.getWeight(new Vector3i(x,y + 1,z)) > 0 ||
|
data.getWeight(currentPos) <= 0 ||
|
||||||
!typeSupportsFoliage(data.getType(new Vector3i(x,y,z)))){
|
data.getWeight(new Vector3i(x,y + 1,z)) > 0 ||
|
||||||
//TODO: destroy
|
!typeSupportsFoliage(data.getType(currentPos))
|
||||||
|
){
|
||||||
|
//destroy
|
||||||
|
FoliageCell toDestroy = locationCellMap.get(key);
|
||||||
|
toDestroy.destroy();
|
||||||
|
activeCells.remove(toDestroy);
|
||||||
|
locationCellMap.remove(key);
|
||||||
} else {
|
} else {
|
||||||
//TODO: evaluate if foliage is placed well
|
//TODO: evaluate if foliage is placed well
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//create if current is ground and above is air
|
//create if current is ground and above is air
|
||||||
if(
|
if(
|
||||||
data.getWeight(new Vector3i(x,y,z)) > 0 &&
|
!locationEvaluationCooldownMap.containsKey(key) &&
|
||||||
|
data.getWeight(currentPos) > 0 &&
|
||||||
data.getWeight(new Vector3i(x,y + 1,z)) < 0 &&
|
data.getWeight(new Vector3i(x,y + 1,z)) < 0 &&
|
||||||
typeSupportsFoliage(data.getType(new Vector3i(x,y,z)))
|
typeSupportsFoliage(data.getType(currentPos))
|
||||||
){
|
){
|
||||||
//create foliage cell
|
//create foliage cell
|
||||||
|
createFoliageCell(worldPos,currentPos,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,14 +245,80 @@ public class ClientFoliageManager {
|
|||||||
if(aboveData != null){
|
if(aboveData != null){
|
||||||
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
||||||
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
||||||
if(data.getWeight(new Vector3i(x,ChunkData.CHUNK_SIZE - 1,z)) > 0 && aboveData.getWeight(new Vector3i(x,0,z)) < 0){
|
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))
|
||||||
|
){
|
||||||
|
//create foliage cell
|
||||||
|
createFoliageCell(worldPos,currentPos,1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a foliage cell at a given position
|
||||||
|
* @param worldPos The world position
|
||||||
|
* @param voxelPos The voxel position
|
||||||
|
*/
|
||||||
|
private void createFoliageCell(Vector3i worldPos, Vector3i voxelPos, float initialGrowthLevel){
|
||||||
|
//get foliage types supported
|
||||||
|
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||||
|
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPos)).getAmbientFoliage();
|
||||||
|
if(foliageTypesSupported != null){
|
||||||
|
FoliageCell cell = new FoliageCell(worldPos, voxelPos);
|
||||||
|
//create center foliage
|
||||||
|
for(int i = 0; i < TARGET_FOLIAGE_PER_CELL; i++){
|
||||||
|
//get type
|
||||||
|
String foliageTypeName = foliageTypesSupported.get(placementRandomizer.nextInt() % foliageTypesSupported.size());
|
||||||
|
FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(foliageTypeName);
|
||||||
|
//get position to place
|
||||||
|
double offsetX = placementRandomizer.nextDouble() * 0.6 + 0.2;
|
||||||
|
double offsetZ = placementRandomizer.nextDouble() * 0.6 + 0.2;
|
||||||
|
Vector3d absolutePosition = new Vector3d(
|
||||||
|
worldPos.x * ChunkData.CHUNK_SIZE + voxelPos.x + offsetX,
|
||||||
|
worldPos.y * ChunkData.CHUNK_SIZE + voxelPos.y + data.getWeight(voxelPos) * 0.6,
|
||||||
|
worldPos.z * ChunkData.CHUNK_SIZE + voxelPos.z + offsetZ
|
||||||
|
);
|
||||||
|
//create entity
|
||||||
|
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||||
|
makeEntityInstancedFoliage(grassEntity, foliageType.getModelPath(), grassCapacity);
|
||||||
|
EntityUtils.getPosition(grassEntity).set(absolutePosition);
|
||||||
|
EntityUtils.getRotation(grassEntity).set(getNewRotation());
|
||||||
|
EntityUtils.getScale(grassEntity).set(new Vector3d(2.0, 2.0, 2.0));
|
||||||
|
//add ambient foliage behavior tree
|
||||||
|
AmbientFoliage.attachAmbientFoliageTree(grassEntity, initialGrowthLevel, foliageType.getGrowthModel().getGrowthRate());
|
||||||
|
cell.addEntity(grassEntity);
|
||||||
|
}
|
||||||
|
activeCells.add(cell);
|
||||||
|
locationCellMap.put(getFoliageCellKey(worldPos, voxelPos),cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether the voxel type supports foliage or not
|
* Gets whether the voxel type supports foliage or not
|
||||||
* @param type
|
* @param type
|
||||||
@ -258,16 +327,24 @@ public class ClientFoliageManager {
|
|||||||
private boolean typeSupportsFoliage(int type){
|
private boolean typeSupportsFoliage(int type){
|
||||||
return Globals.gameConfigCurrent.getVoxelData().getTypeFromId(type).getAmbientFoliage() != null;
|
return Globals.gameConfigCurrent.getVoxelData().getTypeFromId(type).getAmbientFoliage() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate all foliage cells to see if any should be deconstructed and any new ones should be created
|
* Invalidates a foliage cell at a position, destroying all foliage in the cell and unregistering it.
|
||||||
|
* Furthermore, it adds it to a cooldown queue to wait until it can recreate foliage
|
||||||
|
* @param worldPosition The world position of the cell
|
||||||
|
* @param voxelPosition The voxel position of the cell
|
||||||
*/
|
*/
|
||||||
protected void evaluateFoliageCells(){
|
public void invalidateCell(Vector3i worldPosition, Vector3i voxelPosition){
|
||||||
Vector3d playerPosition = EntityUtils.getPosition(Globals.playerEntity);
|
String key = getFoliageCellKey(worldPosition, voxelPosition);
|
||||||
for(FoliageCell activeCell : activeCells){
|
if(!locationEvaluationCooldownMap.containsKey(key)){
|
||||||
//if cell is outside of range of player, disable cell
|
locationEvaluationCooldownMap.put(key,EVALUATION_COOLDOWN);
|
||||||
if(Globals.clientWorldData.convertWorldToRealSpace(activeCell.worldPosition).distance(playerPosition) > CELL_DISTANCE_MAX){
|
FoliageCell cell = locationCellMap.get(key);
|
||||||
//TODO: destroy cell
|
if(cell != null){
|
||||||
|
//destroy
|
||||||
|
FoliageCell toDestroy = locationCellMap.get(key);
|
||||||
|
toDestroy.destroy();
|
||||||
|
activeCells.remove(toDestroy);
|
||||||
|
locationCellMap.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,22 @@
|
|||||||
package electrosphere.client.foliagemanager;
|
package electrosphere.client.foliagemanager;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.joml.Matrix4d;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Quaterniond;
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3f;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.entity.state.foliage.AmbientFoliage;
|
||||||
|
import electrosphere.entity.types.camera.CameraEntityUtils;
|
||||||
|
import electrosphere.renderer.actor.instance.InstancedActor;
|
||||||
|
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains a set of foliage entities and groups them together.
|
* Contains a set of foliage entities and groups them together.
|
||||||
@ -14,9 +25,72 @@ public class FoliageCell {
|
|||||||
//position of the foliage cell in world coordinates
|
//position of the foliage cell in world coordinates
|
||||||
protected Vector3i worldPosition;
|
protected Vector3i worldPosition;
|
||||||
//position of the foliage cell in local coordinates
|
//position of the foliage cell in local coordinates
|
||||||
protected Vector3i localPosition;
|
protected Vector3i voxelPosition;
|
||||||
//constituent entities
|
//constituent entities
|
||||||
protected Set<Entity> containedEntities;
|
protected Set<Entity> containedEntities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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){
|
||||||
|
this.worldPosition = worldPos;
|
||||||
|
this.voxelPosition = voxelPos;
|
||||||
|
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){
|
||||||
|
EntityUtils.cleanUpEntity(entity);
|
||||||
|
}
|
||||||
|
clearEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws all entities in the foliage cell
|
||||||
|
* @param modelMatrixAttribute The model matrix attribute to draw with
|
||||||
|
*/
|
||||||
|
protected void draw(ShaderAttribute modelMatrixAttribute){
|
||||||
|
Matrix4d modelMatrix = new Matrix4d();
|
||||||
|
Vector3f cameraCenter = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
|
||||||
|
Vector3d playerPosition = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
|
for(Entity entity : containedEntities){
|
||||||
|
Vector3d grassPosition = EntityUtils.getPosition(entity);
|
||||||
|
Quaterniond grassRotation = EntityUtils.getRotation(entity);
|
||||||
|
InstancedActor instancedActor = InstancedActor.getInstancedActor(entity);
|
||||||
|
|
||||||
|
modelMatrix = modelMatrix.identity();
|
||||||
|
Vector3f cameraModifiedPosition = new Vector3f((float)grassPosition.x,(float)grassPosition.y,(float)grassPosition.z).sub(cameraCenter);
|
||||||
|
modelMatrix.translate(cameraModifiedPosition);
|
||||||
|
modelMatrix.rotate(new Quaterniond(grassRotation));
|
||||||
|
modelMatrix.scale(new Vector3d(EntityUtils.getScale(entity)));
|
||||||
|
|
||||||
|
instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f(modelMatrix));
|
||||||
|
|
||||||
|
//set priority equal to distance
|
||||||
|
instancedActor.setPriority((int)grassPosition.distance(playerPosition));
|
||||||
|
|
||||||
|
//draw
|
||||||
|
instancedActor.draw(Globals.renderingEngine.getRenderPipelineState());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
package electrosphere.client.terrain.cache;
|
package electrosphere.client.terrain.cache;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
@ -19,6 +22,10 @@ public class ChunkData {
|
|||||||
//How much of that terrain type is in this voxel
|
//How much of that terrain type is in this voxel
|
||||||
float[][][] voxelWeight;
|
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
|
* Gets the voxel type array in this container
|
||||||
@ -33,6 +40,22 @@ public class ChunkData {
|
|||||||
* @param voxelType The voxel type array
|
* @param voxelType The voxel type array
|
||||||
*/
|
*/
|
||||||
public void setVoxelType(int[][][] voxelType){
|
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;
|
this.voxelType = voxelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,6 +72,22 @@ public class ChunkData {
|
|||||||
* @param voxelWeight The voxel weight array
|
* @param voxelWeight The voxel weight array
|
||||||
*/
|
*/
|
||||||
public void setVoxelWeight(float[][][] voxelWeight){
|
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;
|
this.voxelWeight = voxelWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +102,11 @@ public class ChunkData {
|
|||||||
public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
||||||
voxelWeight[localX][localY][localZ] = weight;
|
voxelWeight[localX][localY][localZ] = weight;
|
||||||
voxelType[localX][localY][localZ] = type;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,5 +127,34 @@ public class ChunkData {
|
|||||||
return voxelType[localPosition.x][localPosition.y][localPosition.z];
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,12 +61,12 @@ public class DrawCell {
|
|||||||
rVal.worldPos = worldPos;
|
rVal.worldPos = worldPos;
|
||||||
rVal.program = program;
|
rVal.program = program;
|
||||||
rVal.data = data;
|
rVal.data = data;
|
||||||
|
System.out.println("Create cell");
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a drawable entity based on this chunk
|
* Generates a drawable entity based on this chunk
|
||||||
* @param stride The stride between indices used to generate "sparse" meshes
|
|
||||||
*/
|
*/
|
||||||
public void generateDrawableEntity(){
|
public void generateDrawableEntity(){
|
||||||
if(modelEntity != null){
|
if(modelEntity != null){
|
||||||
@ -94,6 +94,11 @@ public class DrawCell {
|
|||||||
// modelEntity.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
|
// modelEntity.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
|
||||||
// LoggerInterface.loggerRenderer.INFO("New cell @ " + cellX * dynamicInterpolationRatio + "," + cellY * dynamicInterpolationRatio);
|
// LoggerInterface.loggerRenderer.INFO("New cell @ " + cellX * dynamicInterpolationRatio + "," + cellY * dynamicInterpolationRatio);
|
||||||
// EntityUtils.getPosition(modelEntity).set(getRealPos());
|
// EntityUtils.getPosition(modelEntity).set(getRealPos());
|
||||||
|
for(Vector3i position : data.getModifiedPositions()){
|
||||||
|
Globals.clientFoliageManager.invalidateCell(worldPos, position);
|
||||||
|
}
|
||||||
|
data.resetModifiedPositions();
|
||||||
|
|
||||||
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
|
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,19 +110,6 @@ public class DrawCell {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void generatePhysics(){
|
|
||||||
// //if we're in no-graphics mode, need to generate the entity
|
|
||||||
// if(modelEntity == null){
|
|
||||||
// modelEntity = EntityCreationUtils.createClientSpatialEntity();
|
|
||||||
// modelEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
|
||||||
// EntityUtils.getPosition(modelEntity).set(new Vector3f(cellX * dynamicInterpolationRatio, 0.0f, cellY * dynamicInterpolationRatio));
|
|
||||||
// }
|
|
||||||
// //then actually perform the attach
|
|
||||||
// physicsObject = PhysicsUtils.attachTerrainRigidBody(modelEntity,heightmap,false);
|
|
||||||
// Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(modelEntity);
|
|
||||||
// // System.out.println("generate physics");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys a drawcell including its physics
|
* Destroys a drawcell including its physics
|
||||||
*/
|
*/
|
||||||
@ -126,5 +118,13 @@ public class DrawCell {
|
|||||||
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
|
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
|
||||||
EntityUtils.cleanUpEntity(modelEntity);
|
EntityUtils.cleanUpEntity(modelEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current chunk data for this draw cell
|
||||||
|
* @return The chunk data
|
||||||
|
*/
|
||||||
|
public ChunkData getData(){
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -206,8 +206,6 @@ public class DrawCellManager {
|
|||||||
// }
|
// }
|
||||||
keyCellMap.get(targetKey).destroy();
|
keyCellMap.get(targetKey).destroy();
|
||||||
keyCellMap.get(targetKey).generateDrawableEntity();
|
keyCellMap.get(targetKey).generateDrawableEntity();
|
||||||
//evaluate for foliage
|
|
||||||
Globals.clientFoliageManager.evaluateChunk(worldPos);
|
|
||||||
}
|
}
|
||||||
drawable.add(targetKey);
|
drawable.add(targetKey);
|
||||||
}
|
}
|
||||||
@ -399,6 +397,12 @@ public class DrawCellManager {
|
|||||||
return new Vector3i(Integer.parseInt(keyComponents[0]),Integer.parseInt(keyComponents[1]),Integer.parseInt(keyComponents[2]));
|
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){
|
public void markUpdateable(int chunkX, int chunkY, int chunkZ){
|
||||||
updateable.add(getCellKey(chunkX, chunkY, chunkZ));
|
updateable.add(getCellKey(chunkX, chunkY, chunkZ));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,22 +112,6 @@ public class ClientTerrainManager {
|
|||||||
clientWorldData.convertRealToChunkSpace(z)
|
clientWorldData.convertRealToChunkSpace(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is only for short term testing and should be removed
|
|
||||||
* @param worldX
|
|
||||||
* @param worldY
|
|
||||||
* @param worldZ
|
|
||||||
* @param localX
|
|
||||||
* @param localY
|
|
||||||
* @param localZ
|
|
||||||
* @param weight
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
public void updateChunk(int worldX, int worldY, int worldZ, int localX, int localY, int localZ, float weight, int type){
|
|
||||||
terrainCache.getSubChunkDataAtPoint(worldX, worldY, worldZ).updatePosition(localX, localY, localZ, weight, type);
|
|
||||||
Globals.drawCellManager.markUpdateable(worldX, worldY, worldZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the chunk data at a given world position
|
* Gets the chunk data at a given world position
|
||||||
|
|||||||
@ -943,7 +943,7 @@ public class ControlHandler {
|
|||||||
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
|
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
|
||||||
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
|
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
|
||||||
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
|
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
|
||||||
TerrainEditing.editTerrain(cursorPos, 1.1f, 1, 0.01f);
|
TerrainEditing.editTerrain(cursorPos, 1.1f, 2, 0.01f);
|
||||||
}
|
}
|
||||||
}});
|
}});
|
||||||
controls.get(INPUT_CODE_PLACE_TERRAIN).setOnRepeat(new ControlMethod(){public void execute(){
|
controls.get(INPUT_CODE_PLACE_TERRAIN).setOnRepeat(new ControlMethod(){public void execute(){
|
||||||
@ -956,7 +956,7 @@ public class ControlHandler {
|
|||||||
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
|
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
|
||||||
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
|
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
|
||||||
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
|
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
|
||||||
TerrainEditing.editTerrain(cursorPos, 1.1f, 1, 0.01f);
|
TerrainEditing.editTerrain(cursorPos, 1.1f, 2, 0.01f);
|
||||||
}
|
}
|
||||||
}});
|
}});
|
||||||
controls.get(INPUT_CODE_PLACE_TERRAIN).setRepeatTimeout(0.2f * Main.targetFrameRate);
|
controls.get(INPUT_CODE_PLACE_TERRAIN).setRepeatTimeout(0.2f * Main.targetFrameRate);
|
||||||
|
|||||||
@ -136,7 +136,7 @@ public class Main {
|
|||||||
|
|
||||||
|
|
||||||
//debug: create terrain/world viewer
|
//debug: create terrain/world viewer
|
||||||
TerrainViewer.runViewer();
|
// TerrainViewer.runViewer();
|
||||||
|
|
||||||
//create the drawing context
|
//create the drawing context
|
||||||
if(Globals.RUN_CLIENT && !Globals.HEADLESS){
|
if(Globals.RUN_CLIENT && !Globals.HEADLESS){
|
||||||
|
|||||||
@ -224,6 +224,7 @@ public class EntityDataStrings {
|
|||||||
*/
|
*/
|
||||||
public static final String FOLIAGE_IS_FOLIAGE = "foliageIsFoliage";
|
public static final String FOLIAGE_IS_FOLIAGE = "foliageIsFoliage";
|
||||||
public static final String FOLIAGE_TYPE = "foliageType";
|
public static final String FOLIAGE_TYPE = "foliageType";
|
||||||
|
public static final String FOLIAGE_AMBIENT_TREE = "foliageAmbientTree";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Equip state
|
Equip state
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
package electrosphere.entity.state.foliage;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityDataStrings;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.entity.state.BehaviorTree;
|
||||||
|
import electrosphere.entity.types.camera.CameraEntityUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behavior tree for ambient foliage. Controls regrowing, wind movement, etc
|
||||||
|
*/
|
||||||
|
public class AmbientFoliage implements BehaviorTree {
|
||||||
|
|
||||||
|
//the parent entity
|
||||||
|
Entity parent;
|
||||||
|
|
||||||
|
//The current offset by wind (used to snap back to 0)
|
||||||
|
float windOffset = 0;
|
||||||
|
//The current growth level
|
||||||
|
float growthLevel = MAX_GROWTH_LEVEL;
|
||||||
|
//The increment to increase growth level to until 1
|
||||||
|
float growthRate = MAX_GROWTH_LEVEL;
|
||||||
|
//the maximum growth level
|
||||||
|
static final float MAX_GROWTH_LEVEL = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param parent The parent entity
|
||||||
|
* @param regrowFactor The initial growth level
|
||||||
|
* @param growthRate The growth rate
|
||||||
|
*/
|
||||||
|
private AmbientFoliage(Entity parent, float growthLevel, float growthRate){
|
||||||
|
this.growthLevel = growthLevel;
|
||||||
|
this.growthRate = growthRate;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simulate(float deltaTime) {
|
||||||
|
//increase growth factor if relevant
|
||||||
|
if(growthLevel < MAX_GROWTH_LEVEL){
|
||||||
|
growthLevel = growthLevel + growthRate;
|
||||||
|
if(growthLevel > MAX_GROWTH_LEVEL){
|
||||||
|
growthLevel = MAX_GROWTH_LEVEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntityUtils.getScale(parent).set(growthLevel);
|
||||||
|
|
||||||
|
//rotate to face cameras
|
||||||
|
// Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera);
|
||||||
|
// EntityUtils.getRotation(parent).rotateTo(new Vector3d(1,0,0), new Vector3d(cameraEyeVector));
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: simulate wind offset
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches an ambient foliage behavior tree to the provided entity
|
||||||
|
* @param parent The entity
|
||||||
|
* @param growthLevel The initial growth level of the foliage
|
||||||
|
* @param growthRate The rate of growth of the foliage
|
||||||
|
*/
|
||||||
|
public static void attachAmbientFoliageTree(Entity parent, float growthLevel, float growthRate){
|
||||||
|
AmbientFoliage tree = new AmbientFoliage(parent, growthLevel, growthRate);
|
||||||
|
parent.putData(EntityDataStrings.FOLIAGE_AMBIENT_TREE, tree);
|
||||||
|
Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ambient foliage tree on a given entity if it exists
|
||||||
|
* @param entity The entity
|
||||||
|
* @return The ambient foliage tree if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public static AmbientFoliage getAmbientFoliageTree(Entity entity){
|
||||||
|
return (AmbientFoliage) entity.getData(EntityDataStrings.FOLIAGE_AMBIENT_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,30 +3,62 @@ package electrosphere.game.data.foliage.type;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* A foliage object, ambient or otherwise
|
||||||
* @author amaterasu
|
|
||||||
*/
|
*/
|
||||||
public class FoliageType {
|
public class FoliageType {
|
||||||
|
|
||||||
|
//Denotes an ambient foliage that will be placed on a voxel
|
||||||
|
public static final String TOKEN_AMBIENT = "AMBIENT";
|
||||||
|
|
||||||
|
//the name of the foliage type
|
||||||
String name;
|
String name;
|
||||||
|
//the model path of the foliage
|
||||||
String modelPath;
|
String modelPath;
|
||||||
|
//the physics object(s) for the foliage
|
||||||
List<PhysicsObject> physicsObjects;
|
List<PhysicsObject> physicsObjects;
|
||||||
|
//the model of growth characterists
|
||||||
|
GrowthModel growthModel;
|
||||||
|
//the list of tokens
|
||||||
List<String> tokens;
|
List<String> tokens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the foliage type
|
||||||
|
* @return The name
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the model path of the foliage type
|
||||||
|
* @return The model path
|
||||||
|
*/
|
||||||
public String getModelPath() {
|
public String getModelPath() {
|
||||||
return modelPath;
|
return modelPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the physics object(s)
|
||||||
|
* @return The physics object(s)
|
||||||
|
*/
|
||||||
public List<PhysicsObject> getPhysicsObjects() {
|
public List<PhysicsObject> getPhysicsObjects() {
|
||||||
return physicsObjects;
|
return physicsObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tokens
|
||||||
|
* @return The tokens
|
||||||
|
*/
|
||||||
public List<String> getTokens() {
|
public List<String> getTokens() {
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the growth model
|
||||||
|
* @return The growth model
|
||||||
|
*/
|
||||||
|
public GrowthModel getGrowthModel(){
|
||||||
|
return growthModel;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
package electrosphere.game.data.foliage.type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of the growth characteristics of this piece of foliage
|
||||||
|
*/
|
||||||
|
public class GrowthModel {
|
||||||
|
|
||||||
|
//the rate at which the foliage will grow
|
||||||
|
float growthRate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the growth rate
|
||||||
|
* @return the growth rate
|
||||||
|
*/
|
||||||
|
public float getGrowthRate(){
|
||||||
|
return growthRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package electrosphere.game.data.voxel;
|
package electrosphere.game.data.voxel;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data about a particular type of voxel
|
* Data about a particular type of voxel
|
||||||
@ -11,7 +11,7 @@ public class VoxelType {
|
|||||||
//the name of the type
|
//the name of the type
|
||||||
String name;
|
String name;
|
||||||
//any ambient foliage that can be placed on this voxel type
|
//any ambient foliage that can be placed on this voxel type
|
||||||
Set<String> ambientFoliage;
|
List<String> ambientFoliage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the id of the voxel type
|
* Gets the id of the voxel type
|
||||||
@ -33,7 +33,7 @@ public class VoxelType {
|
|||||||
* Gets the names of all ambient foliage that can be placed on this voxel type
|
* Gets the names of all ambient foliage that can be placed on this voxel type
|
||||||
* @return The set of names
|
* @return The set of names
|
||||||
*/
|
*/
|
||||||
public Set<String> getAmbientFoliage(){
|
public List<String> getAmbientFoliage(){
|
||||||
return ambientFoliage;
|
return ambientFoliage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1492,6 +1492,10 @@ public class RenderingEngine {
|
|||||||
Globals.projectionMatrix.setPerspective(radVerticalFOV, RenderingEngine.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
|
Globals.projectionMatrix.setPerspective(radVerticalFOV, RenderingEngine.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current render pipeline state
|
||||||
|
* @return The current render pipeline state
|
||||||
|
*/
|
||||||
public RenderPipelineState getRenderPipelineState(){
|
public RenderPipelineState getRenderPipelineState(){
|
||||||
return renderPipelineState;
|
return renderPipelineState;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public class InstanceData {
|
|||||||
int drawCalls = 0;
|
int drawCalls = 0;
|
||||||
|
|
||||||
//The priority queue of instanced actors to draw
|
//The priority queue of instanced actors to draw
|
||||||
PriorityQueue<InstancedActor> actorQueue = new PriorityQueue<InstancedActor>(1000);
|
PriorityQueue<InstancedActor> actorQueue = null;
|
||||||
//Map of actor to index in the buffers that are emitted
|
//Map of actor to index in the buffers that are emitted
|
||||||
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
|
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
|
||||||
//Map of index -> actor used for buffer evictions
|
//Map of index -> actor used for buffer evictions
|
||||||
@ -60,6 +60,7 @@ public class InstanceData {
|
|||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
this.vertexShaderPath = vertexPath;
|
this.vertexShaderPath = vertexPath;
|
||||||
this.fragmentShaderPath = fragmentPath;
|
this.fragmentShaderPath = fragmentPath;
|
||||||
|
actorQueue = new PriorityQueue<InstancedActor>(this.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -275,53 +276,12 @@ public class InstanceData {
|
|||||||
}
|
}
|
||||||
//increment
|
//increment
|
||||||
i++;
|
i++;
|
||||||
if(i > capacity){
|
if(i >= capacity){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//reset all buffers
|
//reset all buffers
|
||||||
for(ShaderAttribute attribute : attributeIndices){
|
flip();
|
||||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
|
||||||
case VEC3F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
case VEC3D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
case VEC4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
case VEC4D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
case MAT4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
// System.out.println(buffer.position() + " " + buffer.limit());
|
|
||||||
} break;
|
|
||||||
case MAT4D: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
// System.out.println(buffer.position() + " " + buffer.limit());
|
|
||||||
} break;
|
|
||||||
case DOUBLE: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
case FLOAT: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
case INT: {
|
|
||||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.flip();
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void flip(){
|
protected void flip(){
|
||||||
|
|||||||
@ -27,7 +27,6 @@ public class InstanceManager {
|
|||||||
/**
|
/**
|
||||||
* Adds an instanced actor to the list of actors to be priority sorted into drawn and not drawn
|
* Adds an instanced actor to the list of actors to be priority sorted into drawn and not drawn
|
||||||
* @param actor The instanced actor
|
* @param actor The instanced actor
|
||||||
* @param priority The priority of this actor
|
|
||||||
*/
|
*/
|
||||||
protected void addToQueue(InstancedActor actor){
|
protected void addToQueue(InstancedActor actor){
|
||||||
InstanceData data = pathToInstanceData.get(actor.getModelPath());
|
InstanceData data = pathToInstanceData.get(actor.getModelPath());
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import electrosphere.renderer.RenderPipelineState;
|
|||||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instanced actor is a static (not animated) actor for an instanced model (eg grass, trees, leaves, rocks, etc)
|
* An instanced actor is a static (not bone animated) actor for an instanced model (eg grass, trees, leaves, rocks, etc)
|
||||||
*/
|
*/
|
||||||
public class InstancedActor implements Comparable<InstancedActor> {
|
public class InstancedActor implements Comparable<InstancedActor> {
|
||||||
//path of the model that this instanced actor uses
|
//path of the model that this instanced actor uses
|
||||||
@ -107,4 +107,20 @@ public class InstancedActor implements Comparable<InstancedActor> {
|
|||||||
return (InstancedActor)entity.getData(EntityDataStrings.INSTANCED_ACTOR);
|
return (InstancedActor)entity.getData(EntityDataStrings.INSTANCED_ACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the draw priority of the instanced actor
|
||||||
|
* @param priority The priority value (lower is higher priority)
|
||||||
|
*/
|
||||||
|
public void setPriority(int priority){
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the priority of this instanced actor
|
||||||
|
* @return The priority of the instanced actor
|
||||||
|
*/
|
||||||
|
public int getPriority(){
|
||||||
|
return this.priority;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ public class ServerTerrainChunk {
|
|||||||
for(int weightX = 0; weightX < CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
for(int weightX = 0; weightX < CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
||||||
for(int weightZ = 0; weightZ < CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
for(int weightZ = 0; weightZ < CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
||||||
weights[weightX][0][weightZ] = 0.1f;
|
weights[weightX][0][weightZ] = 0.1f;
|
||||||
values[weightX][0][weightZ] = 1;
|
values[weightX][0][weightZ] = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user