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; | ||||||
| 
 | 
 | ||||||
| @ -41,9 +40,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(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)) | ||||||
|                             //TODO: destroy |                         ){ | ||||||
|  |                             //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,11 +245,77 @@ 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); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -260,14 +329,22 @@ public class ClientFoliageManager { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 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 | ||||||
|      */ |      */ | ||||||
| @ -127,4 +119,12 @@ public class DrawCell { | |||||||
|         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)); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -113,22 +113,6 @@ public class ClientTerrainManager { | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |  | ||||||
|      * 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 | ||||||
|      * @param worldX The x component of the world coordinate |      * @param worldX The x component of the world coordinate | ||||||
|  | |||||||
| @ -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