Renderer/src/main/java/electrosphere/game/terrain/TerrainManager.java
2021-04-04 21:56:35 -04:00

149 lines
5.2 KiB
Java

package electrosphere.game.terrain;
import com.google.gson.Gson;
import electrosphere.main.Globals;
import electrosphere.terraingen.TerrainGen;
import electrosphere.terraingen.models.TerrainModel;
import electrosphere.util.Utilities;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
/**
*
* @author satellite
*/
public class TerrainManager {
//The size of the world in discrete units * must be multiple of 200
int worldSizeDiscrete = 2000;
//The vertical multiplier applied to the statically generated terrain
int verticalInterpolationRatio = 20;
int dynamicInterpolationRatio = 1000;
TerrainModel model;
//Basic idea is we associate string that contains chunk x&y with elevation
//While we incur a penalty with converting ints -> string, think this will
//offset regenerating the array every time we want a new one
int cacheSize = 50;
HashMap<String, float[][]> elevationMapCache;
ArrayList<String> elevationMapCacheContents;
public TerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, int dynamicInterpolationRatio){
this.worldSizeDiscrete = worldSizeDiscrete;
this.verticalInterpolationRatio = verticalInterpolationRatio;
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
this.elevationMapCache = new HashMap();
this.elevationMapCacheContents = new ArrayList();
}
public void generate(){
TerrainGen terrainGen = new TerrainGen();
terrainGen.setInterpolationRatio(worldSizeDiscrete/200);
terrainGen.setVerticalInterpolationRatio(verticalInterpolationRatio);
terrainGen.setDynamicInterpolationRatio(dynamicInterpolationRatio);
terrainGen.setRandomSeed(0);
model = terrainGen.generateModel();
}
public void save(){
Gson gson = new Gson();
String terrainOutRaw = gson.toJson(model);
try {
Files.write(new File(Globals.mainConfig.loadTerrainLocation).toPath(), terrainOutRaw.getBytes());
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void load(){
Gson gson = new Gson();
model = gson.fromJson(Utilities.readFileToString(new File(Globals.mainConfig.loadTerrainLocation)), TerrainModel.class);
}
public float[][] getTerrainAtChunk(int x, int y){
return model.getElevationForChunk(x, y);
}
public float[][] getAugmentedTerrainAtChunk(int x, int y){
String targetChunkName = x + "-" + y;
if(elevationMapCache.containsKey(targetChunkName)){
elevationMapCacheContents.remove(targetChunkName);
elevationMapCacheContents.add(0, targetChunkName);
return elevationMapCache.get(targetChunkName);
} else {
float[][] targetChunk = model.getAugmentedElevationForChunk(x, y);
if(elevationMapCacheContents.size() > cacheSize){
String oldChunk = elevationMapCacheContents.remove(elevationMapCacheContents.size() - 1);
elevationMapCache.remove(oldChunk);
}
elevationMapCache.put(targetChunkName, targetChunk);
elevationMapCacheContents.add(targetChunkName);
return targetChunk;
}
}
public float getHeightAtPosition(float x, float y){
//get chunk coordinate space of input x,y
int chunkX = (int)Math.floor(x / dynamicInterpolationRatio);
int chunkY = (int)Math.floor(y / dynamicInterpolationRatio);
//get local coordinate space of input x,y
float localX = x - chunkX * dynamicInterpolationRatio;
float localY = y - chunkY * dynamicInterpolationRatio;
//get chunk elevation map
float[][] chunkElevationMap = getAugmentedTerrainAtChunk(chunkX,chunkY);
//floored variants of local values
int localXf = (int)Math.floor(localX);
int localYf = (int)Math.floor(localY);
/*
Average some inner value.
01 11
0.3 0.4 0.5
0.1 0.2 0.3
00 10
*/
//interp elevation from map
float elevation00 = chunkElevationMap[(int)localX+0][(int)localY+0];
float elevation10 = chunkElevationMap[(int)localX+1][(int)localY+0];
float elevation01 = chunkElevationMap[(int)localX+0][(int)localY+1];
float elevation11 = chunkElevationMap[(int)localX+1][(int)localY+1];
float rVal =
(1-(localX-localXf))*(1-(localY-localYf)) * elevation00 +
( (localX-localXf))*(1-(localY-localYf)) * elevation10 +
(1-(localX-localXf))*( (localY-localYf)) * elevation01 +
( (localX-localXf))*( (localY-localYf)) * elevation11
;
return rVal;
}
public int getChunkWidth(){
return dynamicInterpolationRatio;
}
public int getAugmentedChunkWidth(){
return dynamicInterpolationRatio + 1;
}
public int getWorldDiscreteSize(){
return worldSizeDiscrete;
}
public float getDiscreteValue(int x, int y){
return model.getElevation()[x][y];
}
}