Terrain chunking wip
This commit is contained in:
parent
34c5776296
commit
5d4e5bc775
42
src/main/java/electrosphere/entity/EntityManager.java
Normal file
42
src/main/java/electrosphere/entity/EntityManager.java
Normal file
@ -0,0 +1,42 @@
|
||||
package electrosphere.entity;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author satellite
|
||||
*/
|
||||
public class EntityManager {
|
||||
|
||||
static CopyOnWriteArrayList<Entity> entityList;
|
||||
static CopyOnWriteArrayList<Entity> drawableList;
|
||||
|
||||
public EntityManager(){
|
||||
entityList = new CopyOnWriteArrayList();
|
||||
drawableList = new CopyOnWriteArrayList();
|
||||
}
|
||||
|
||||
public void registerEntity(Entity e){
|
||||
entityList.add(e);
|
||||
}
|
||||
|
||||
public void registerDrawableEntity(Entity e){
|
||||
drawableList.add(e);
|
||||
}
|
||||
|
||||
public Iterator<Entity> getDrawableIterator(){
|
||||
return drawableList.iterator();
|
||||
}
|
||||
|
||||
public void deregisterEntity(Entity e){
|
||||
if(drawableList.contains(e)){
|
||||
drawableList.remove(e);
|
||||
EntityUtil.cleanUpDrawableEntity(e);
|
||||
}
|
||||
if(entityList.contains(e)){
|
||||
entityList.remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -38,8 +38,12 @@ public class EntityUtil {
|
||||
rVal.putData("position", new Vector3f(0,0,0));
|
||||
rVal.putData("rotation", new Quaternionf().rotateAxis((float)0, new Vector3f(1,0,0)));
|
||||
rVal.putData("scale", new Vector3f(1,1,1));
|
||||
Globals.entityList.add(rVal);
|
||||
Globals.drawableList.add(rVal);
|
||||
Globals.entityManager.registerEntity(rVal);
|
||||
Globals.entityManager.registerDrawableEntity(rVal);
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public static void cleanUpDrawableEntity(Entity e){
|
||||
getEntityModel(e).free();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,20 +1,163 @@
|
||||
package electrosphere.game.cell;
|
||||
|
||||
import electrosphere.game.terrain.TerrainManager;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author satellite
|
||||
*/
|
||||
public class CellManager {
|
||||
|
||||
//the terrain manager this cell manager constructs off of
|
||||
TerrainManager terrainManager;
|
||||
|
||||
//the center of this cell manager's array in cell space
|
||||
int cellX;
|
||||
int cellY;
|
||||
|
||||
//the width of a minicell in this manager
|
||||
int miniCellWidth;
|
||||
|
||||
//all currently displaying mini cells
|
||||
DrawCell[][] cells;
|
||||
boolean[][] valid;
|
||||
boolean[][] drawable;
|
||||
|
||||
|
||||
|
||||
|
||||
int drawRadius = 5;
|
||||
int drawStepdownInterval = 2;
|
||||
int drawStepdownValue = 10;
|
||||
|
||||
public CellManager(){
|
||||
public CellManager(TerrainManager terrainManager, float realX, int realY){
|
||||
this.terrainManager = terrainManager;
|
||||
this.miniCellWidth = miniCellWidth;
|
||||
cells = new DrawCell[drawRadius * 2 + 1][drawRadius * 2 + 1];
|
||||
|
||||
valid = new boolean[drawRadius * 2 + 1][drawRadius * 2 + 1];
|
||||
drawable = new boolean[drawRadius * 2 + 1][drawRadius * 2 + 1];
|
||||
for(int x = 0; x < drawRadius * 2 + 1; x++){
|
||||
for(int y = 0; y < drawRadius * 2 + 1; y++){
|
||||
valid[x][y] = false;
|
||||
drawable[x][y] = false;
|
||||
}
|
||||
}
|
||||
cellX = transformRealSpaceToCellSpace(realX);
|
||||
cellY = transformRealSpaceToCellSpace(realY);
|
||||
}
|
||||
|
||||
public int getCellX(){
|
||||
return cellX;
|
||||
}
|
||||
|
||||
public int getCellY(){
|
||||
return cellY;
|
||||
}
|
||||
|
||||
public void setCellX(int x){
|
||||
cellX = x;
|
||||
}
|
||||
|
||||
public void setCellY(int y){
|
||||
cellY = y;
|
||||
}
|
||||
|
||||
public void updateInvalidCell(){
|
||||
int targetX = 0;
|
||||
int targetY = 0;
|
||||
boolean found = false;
|
||||
for(int x = 0; x < drawRadius * 2 + 1; x++){
|
||||
targetX = x;
|
||||
for(int y = 0; y < drawRadius * 2 + 1; y++){
|
||||
targetY = y;
|
||||
if(!valid[x][y]){
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found){
|
||||
int currentCellX = cellX - drawRadius + targetX;
|
||||
int currentCellY = cellY - drawRadius + targetY;
|
||||
if(
|
||||
currentCellX >= 0 &&
|
||||
currentCellX < terrainManager.getWorldDiscreteSize() &&
|
||||
currentCellY >= 0 &&
|
||||
currentCellY < terrainManager.getWorldDiscreteSize()
|
||||
){
|
||||
cells[targetX][targetY] = new DrawCell(terrainManager.getTerrainAtChunk(cellX, cellY),cellX,cellY,terrainManager.getChunkWidth());
|
||||
}
|
||||
valid[targetX][targetY] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void makeCellDrawable(){
|
||||
int targetX = 0;
|
||||
int targetY = 0;
|
||||
boolean found = false;
|
||||
for(int x = 0; x < drawRadius * 2 + 1; x++){
|
||||
targetX = x;
|
||||
for(int y = 0; y < drawRadius * 2 + 1; y++){
|
||||
targetY = y;
|
||||
if(valid[x][y] && !drawable[x][y]){
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found){
|
||||
int currentCellX = cellX - drawRadius + targetX;
|
||||
int currentCellY = cellY - drawRadius + targetY;
|
||||
if(
|
||||
currentCellX >= 0 &&
|
||||
currentCellX < terrainManager.getWorldDiscreteSize() &&
|
||||
currentCellY >= 0 &&
|
||||
currentCellY < terrainManager.getWorldDiscreteSize()
|
||||
){
|
||||
int dist = Math.abs(cellX - drawRadius) * Math.abs(cellY - drawRadius);
|
||||
int stride = Math.max(100, dist / drawStepdownInterval * drawStepdownValue);
|
||||
cells[targetX][targetY].generateDrawableEntity(stride);
|
||||
}
|
||||
drawable[targetX][targetY] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean containsInvalidCell(){
|
||||
for(int x = 0;x < drawRadius * 2 + 1; x++){
|
||||
for(int y = 0; y < drawRadius * 2 + 1; y++){
|
||||
if(!valid[x][y]){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsUndrawableCell(){
|
||||
for(int x = 0;x < drawRadius * 2 + 1; x++){
|
||||
for(int y = 0; y < drawRadius * 2 + 1; y++){
|
||||
if(!drawable[x][y]){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public int transformRealSpaceToCellSpace(float input){
|
||||
return (int)input / terrainManager.getChunkWidth();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -2,8 +2,10 @@ package electrosphere.game.cell;
|
||||
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityUtil;
|
||||
import electrosphere.main.Globals;
|
||||
import electrosphere.renderer.Model;
|
||||
import electrosphere.util.Utilities;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -12,19 +14,31 @@ import electrosphere.util.Utilities;
|
||||
public class DrawCell {
|
||||
float[][] elevation;
|
||||
|
||||
public DrawCell(float[][] elevation){
|
||||
int cellX;
|
||||
int cellY;
|
||||
int cellWidth;
|
||||
|
||||
Entity modelEntity;
|
||||
|
||||
public DrawCell(float[][] elevation, int cellX, int cellY, int cellWidth){
|
||||
this.elevation = elevation;
|
||||
this.cellX = cellX;
|
||||
this.cellY = cellY;
|
||||
this.cellWidth = cellWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a drawable entity based on this chunk
|
||||
* @param stride The stride between indices used to generate "sparse" meshes
|
||||
* @return A drawable entity that contains the terrain mesh of a certain stride
|
||||
*/
|
||||
public Entity generateDrawableEntity(int stride){
|
||||
public void generateDrawableEntity(int stride){
|
||||
if(modelEntity != null){
|
||||
Globals.entityManager.deregisterEntity(modelEntity);
|
||||
}
|
||||
Model terrainModel = Utilities.create_terrain_model(elevation, stride);
|
||||
Entity rVal = EntityUtil.spawnDrawableEntity(terrainModel);
|
||||
return rVal;
|
||||
modelEntity = EntityUtil.spawnDrawableEntity(terrainModel);
|
||||
// System.out.println("New cell @ " + cellX * cellWidth + "," + cellY * cellWidth);
|
||||
EntityUtil.getEntityPosition(modelEntity).set(new Vector3f(cellX * cellWidth, 0, cellY * cellWidth));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,21 +15,19 @@ import java.nio.file.Files;
|
||||
*/
|
||||
public class TerrainManager {
|
||||
|
||||
//This is the dimension in x and y of the chunk
|
||||
int chunkSize = 200;
|
||||
|
||||
//The size of the world in discrete units * must be multiple of 200
|
||||
int worldSizeDiscrete = 2000;
|
||||
|
||||
int dynamicInterpolationRatio = 200;
|
||||
int dynamicInterpolationRatio = 1000;
|
||||
|
||||
TerrainModel model;
|
||||
|
||||
|
||||
|
||||
public TerrainManager(int chunkSize, int worldSizeDiscrete){
|
||||
this.chunkSize = chunkSize;
|
||||
public TerrainManager(int worldSizeDiscrete, int dynamicInterpolationRatio){
|
||||
this.worldSizeDiscrete = worldSizeDiscrete;
|
||||
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
||||
}
|
||||
|
||||
public void generate(){
|
||||
@ -61,11 +59,11 @@ public class TerrainManager {
|
||||
|
||||
public float getHeightAtPosition(float x, float y){
|
||||
//get chunk coordinate space of input x,y
|
||||
int chunkX = (int)Math.floor(x / chunkSize);
|
||||
int chunkY = (int)Math.floor(y / chunkSize);
|
||||
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 * chunkSize;
|
||||
float localY = y - chunkY * chunkSize;
|
||||
float localX = x - chunkX * dynamicInterpolationRatio;
|
||||
float localY = y - chunkY * dynamicInterpolationRatio;
|
||||
//get chunk elevation map
|
||||
float[][] chunkElevationMap = getTerrainAtChunk(chunkX,chunkY);
|
||||
//floored variants of local values
|
||||
@ -96,5 +94,12 @@ public class TerrainManager {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public int getChunkWidth(){
|
||||
return dynamicInterpolationRatio;
|
||||
}
|
||||
|
||||
public int getWorldDiscreteSize(){
|
||||
return worldSizeDiscrete;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ import electrosphere.renderer.texture.TextureMap;
|
||||
import com.google.gson.Gson;
|
||||
import electrosphere.cfg.MainConfig;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityManager;
|
||||
import electrosphere.game.cell.CellManager;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -64,8 +66,7 @@ public class Globals {
|
||||
|
||||
public static TextureMap textureMapDefault;
|
||||
|
||||
public static CopyOnWriteArrayList<Entity> entityList;
|
||||
public static CopyOnWriteArrayList<Entity> drawableList;
|
||||
public static EntityManager entityManager;
|
||||
|
||||
public static Camera cameraVisible;
|
||||
|
||||
@ -76,11 +77,7 @@ public class Globals {
|
||||
|
||||
//chunk stuff
|
||||
//constant for how far in game units you have to move to load chunks
|
||||
|
||||
|
||||
//array of chunks around view
|
||||
public static boolean[][] loadedChunk;
|
||||
public static Entity[][] chunks;
|
||||
public static CellManager cellManager;
|
||||
|
||||
|
||||
//famous fuckin last words, but temporary solution
|
||||
@ -88,6 +85,10 @@ public class Globals {
|
||||
public static ArrayList<Vector3f> skyboxColors;
|
||||
|
||||
|
||||
//player's entity
|
||||
public static Entity player;
|
||||
|
||||
|
||||
|
||||
public static void initGlobals(){
|
||||
//create default textures
|
||||
@ -106,9 +107,8 @@ public class Globals {
|
||||
//also done in one line
|
||||
textureMapDefault = gson.fromJson(Files.newBufferedReader(new File(Thread.currentThread().getContextClassLoader().getResource("Textures/default_texture_map.json").getFile()).toPath()), TextureMap.class); //only the best of coding practices :)
|
||||
} catch (IOException ex) { ex.printStackTrace(); } //TODO: handle better :tm:
|
||||
//create entity list
|
||||
entityList = new CopyOnWriteArrayList();
|
||||
drawableList = new CopyOnWriteArrayList();
|
||||
//create entity manager
|
||||
entityManager = new EntityManager();
|
||||
//create the camera object that generates view matrix
|
||||
cameraVisible = new Camera();
|
||||
//init game specific variables
|
||||
|
||||
@ -10,6 +10,7 @@ import electrosphere.renderer.ShaderProgram;
|
||||
import electrosphere.renderer.texture.Texture;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityUtil;
|
||||
import electrosphere.game.cell.CellManager;
|
||||
import electrosphere.game.terrain.TerrainManager;
|
||||
import electrosphere.terraingen.TerrainGen;
|
||||
import electrosphere.terraingen.models.TerrainModel;
|
||||
@ -86,6 +87,10 @@ public class Main {
|
||||
public static boolean PLAYER_UNDER_USER_CONTROL = true;
|
||||
public static boolean CAMERA_IS_ORBIT = true;
|
||||
public static float camera_Orbit_Length = 1.0f;
|
||||
|
||||
static final int playerStartRealX = 1000;
|
||||
static final int playerStartRealY = 1000;
|
||||
|
||||
// public static Camera cam_Player_Orbit;
|
||||
//Camera angles using theta-phi system
|
||||
//Euler angles where theta is applied, then phi
|
||||
@ -124,11 +129,7 @@ public class Main {
|
||||
|
||||
initSkybox();
|
||||
|
||||
|
||||
|
||||
Entity player = new Entity();
|
||||
player.putData("position", new Vector3f(0f,6f,0f));
|
||||
|
||||
initPlayer();
|
||||
|
||||
|
||||
|
||||
@ -188,22 +189,22 @@ public class Main {
|
||||
}
|
||||
}
|
||||
if(glfwGetKey(Globals.window, GLFW_KEY_W) == GLFW_PRESS){
|
||||
EntityUtil.getEntityPosition(player).add(new Vector3f(-camera_Current.pos_Center.x,0,-camera_Current.pos_Center.z));
|
||||
EntityUtil.getEntityPosition(Globals.player).add(new Vector3f(-camera_Current.pos_Center.x,0,-camera_Current.pos_Center.z));
|
||||
}
|
||||
if(glfwGetKey(Globals.window, GLFW_KEY_S) == GLFW_PRESS){
|
||||
EntityUtil.getEntityPosition(player).add(new Vector3f(camera_Current.pos_Center.x,0,camera_Current.pos_Center.z));
|
||||
EntityUtil.getEntityPosition(Globals.player).add(new Vector3f(camera_Current.pos_Center.x,0,camera_Current.pos_Center.z));
|
||||
}
|
||||
if(glfwGetKey(Globals.window, GLFW_KEY_D) == GLFW_PRESS){
|
||||
EntityUtil.getEntityPosition(player).add(new Vector3f(-camera_Current.pos_Center.x,0,-camera_Current.pos_Center.z).rotateY((float)(-90 * Math.PI / 180)));
|
||||
EntityUtil.getEntityPosition(Globals.player).add(new Vector3f(-camera_Current.pos_Center.x,0,-camera_Current.pos_Center.z).rotateY((float)(-90 * Math.PI / 180)));
|
||||
}
|
||||
if(glfwGetKey(Globals.window, GLFW_KEY_A) == GLFW_PRESS){
|
||||
EntityUtil.getEntityPosition(player).add(new Vector3f(-camera_Current.pos_Center.x,0,-camera_Current.pos_Center.z).rotateY((float)(90 * Math.PI / 180)));
|
||||
EntityUtil.getEntityPosition(Globals.player).add(new Vector3f(-camera_Current.pos_Center.x,0,-camera_Current.pos_Center.z).rotateY((float)(90 * Math.PI / 180)));
|
||||
}
|
||||
if(glfwGetKey(Globals.window, GLFW_KEY_SPACE) == GLFW_PRESS){
|
||||
EntityUtil.getEntityPosition(player).add(new Vector3f(0,0.6f,0));
|
||||
EntityUtil.getEntityPosition(Globals.player).add(new Vector3f(0,0.6f,0));
|
||||
}
|
||||
if(glfwGetKey(Globals.window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS){
|
||||
EntityUtil.getEntityPosition(player).add(new Vector3f(0,-0.6f,0));
|
||||
EntityUtil.getEntityPosition(Globals.player).add(new Vector3f(0,-0.6f,0));
|
||||
}
|
||||
|
||||
|
||||
@ -222,12 +223,12 @@ public class Main {
|
||||
//
|
||||
// Draw all entities
|
||||
//
|
||||
Iterator<Entity> entity_iterator = Globals.drawableList.iterator();
|
||||
Iterator<Entity> entity_iterator = Globals.entityManager.getDrawableIterator();
|
||||
while(entity_iterator.hasNext()){
|
||||
Entity currentEntity = entity_iterator.next();
|
||||
Model currentModel = EntityUtil.getEntityModel(currentEntity);
|
||||
currentModel.modelMatrix = new Matrix4f();
|
||||
currentModel.modelMatrix.translate(new Vector3f(EntityUtil.getEntityPosition(currentEntity)).sub(EntityUtil.getEntityPosition(player)));
|
||||
currentModel.modelMatrix.translate(new Vector3f(EntityUtil.getEntityPosition(currentEntity)).sub(EntityUtil.getEntityPosition(Globals.player)));
|
||||
currentModel.modelMatrix.rotate(EntityUtil.getEntityRotation(currentEntity));
|
||||
currentModel.modelMatrix.scale(EntityUtil.getEntityScale(currentEntity));
|
||||
currentModel.draw();
|
||||
@ -301,16 +302,39 @@ public class Main {
|
||||
|
||||
|
||||
static void initWorld(){
|
||||
|
||||
float[][] elevation;
|
||||
terrainManager = new TerrainManager(1000,2000);
|
||||
terrainManager = new TerrainManager(2000,200);
|
||||
if(Globals.mainConfig.loadTerrain){
|
||||
terrainManager.load();
|
||||
} else {
|
||||
terrainManager.generate();
|
||||
terrainManager.save();
|
||||
}
|
||||
elevation = terrainManager.getTerrainAtChunk(10, 10);
|
||||
Model terrainModel = Utilities.create_terrain_model(elevation,10);
|
||||
Entity terrainEntity = EntityUtil.spawnDrawableEntity(terrainModel);
|
||||
|
||||
//init cell manager
|
||||
int cellX = 0;
|
||||
int cellY = 0;
|
||||
Globals.cellManager = new CellManager(terrainManager, playerStartRealX, playerStartRealY);
|
||||
|
||||
|
||||
while(Globals.cellManager.containsInvalidCell()){
|
||||
Globals.cellManager.updateInvalidCell();
|
||||
}
|
||||
|
||||
while(Globals.cellManager.containsUndrawableCell()){
|
||||
Globals.cellManager.makeCellDrawable();
|
||||
}
|
||||
|
||||
// elevation = terrainManager.getTerrainAtChunk(10, 10);
|
||||
// Model terrainModel = Utilities.create_terrain_model(elevation,10);
|
||||
// Entity terrainEntity = EntityUtil.spawnDrawableEntity(terrainModel);
|
||||
}
|
||||
|
||||
static void initPlayer(){
|
||||
Globals.player = new Entity();
|
||||
Globals.player.putData("position", new Vector3f(playerStartRealX,6f,playerStartRealY));
|
||||
|
||||
Globals.cellManager.setCellX(GL_S);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,9 +85,9 @@ public class Utilities {
|
||||
int actualWidth = width / stride;
|
||||
int actualHeight = height / stride;
|
||||
|
||||
System.out.println(actualWidth + " " + actualHeight);
|
||||
|
||||
System.out.println((actualWidth - 1) * (actualHeight - 1));
|
||||
// System.out.println(actualWidth + " " + actualHeight);
|
||||
//
|
||||
// System.out.println((actualWidth - 1) * (actualHeight - 1));
|
||||
|
||||
FloatBuffer vertices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 3);
|
||||
FloatBuffer normals = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 3);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user