149 lines
5.2 KiB
Java
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];
|
|
}
|
|
|
|
}
|