package electrosphere.game.cell; import electrosphere.game.terrain.TerrainManager; import electrosphere.renderer.ShaderProgram; 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; boolean[][] updateable; ShaderProgram program; int drawRadius = 1; int drawStepdownInterval = 2; int drawStepdownValue = 20; public CellManager(TerrainManager terrainManager, float realX, float 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]; updateable = 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; updateable[x][y] = false; } } cellX = transformRealSpaceToCellSpace(realX); cellY = transformRealSpaceToCellSpace(realY); program = ShaderProgram.smart_assemble_shader(false, true); } 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.getAugmentedTerrainAtChunk(currentCellX, currentCellY), terrainManager.getAugmentedChunkWidth(), currentCellX, currentCellY, terrainManager.getChunkWidth(), program ); } valid[targetX][targetY] = true; drawable[targetX][targetY] = false; updateable[targetX][targetY] = false; } } 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(targetX - drawRadius) * Math.abs(targetY - drawRadius); int stride = Math.min(100, Math.max(1, dist / drawStepdownInterval * drawStepdownValue)); while(terrainManager.getChunkWidth() % stride != 0){ stride = stride + 1; } cells[targetX][targetY].generateDrawableEntity(stride); } drawable[targetX][targetY] = true; } } public void updateCellModel(){ 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(updateable[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(targetX - drawRadius) * Math.abs(targetY - drawRadius); int stride = Math.min(100, Math.max(1, dist / drawStepdownInterval * drawStepdownValue)); while(terrainManager.getChunkWidth() % stride != 0){ stride = stride + 1; } cells[targetX][targetY].generateDrawableEntity(stride); } updateable[targetX][targetY] = false; 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 boolean containsUpdateableCell(){ for(int x = 0;x < drawRadius * 2 + 1; x++){ for(int y = 0; y < drawRadius * 2 + 1; y++){ if(updateable[x][y]){ return true; } } } return false; } public void shiftChunksNegX(){ for(int y = 0; y < drawRadius * 2 + 1; y++){ cells[drawRadius * 2][y].retireCell(); } for(int x = drawRadius * 2; x > 0; x--){ for(int y = 0; y < drawRadius * 2 + 1; y++){ cells[x][y] = cells[x-1][y]; updateable[x][y] = true; } } for(int y = 0; y < drawRadius * 2 + 1; y++){ valid[0][y] = false; } } public void shiftChunksPosX(){ for(int y = 0; y < drawRadius * 2 + 1; y++){ cells[0][y].retireCell(); } for(int x = 0; x < drawRadius * 2; x++){ for(int y = 0; y < drawRadius * 2 + 1; y++){ cells[x][y] = cells[x+1][y]; updateable[x][y] = true; } } for(int y = 0; y < drawRadius * 2 + 1; y++){ valid[drawRadius * 2][y] = false; } } public void shiftChunksNegY(){ for(int x = 0; x < drawRadius * 2 + 1; x++){ cells[x][drawRadius * 2].retireCell(); } for(int x = 0; x < drawRadius * 2 + 1; x++){ for(int y = drawRadius * 2; y > 0; y--){ cells[x][y] = cells[x][y-1]; updateable[x][y] = true; } } for(int x = 0; x < drawRadius * 2 + 1; x++){ valid[x][0] = false; } } public void shiftChunksPosY(){ for(int x = 0; x < drawRadius * 2 + 1; x++){ cells[x][0].retireCell(); } for(int x = 0; x < drawRadius * 2 + 1; x++){ for(int y = 0; y < drawRadius * 2; y++){ cells[x][y] = cells[x][y+1]; updateable[x][y] = true; } } for(int x = 0; x < drawRadius * 2 + 1; x++){ valid[x][drawRadius * 2] = false; } } public int transformRealSpaceToCellSpace(float input){ return (int)(input / terrainManager.getChunkWidth()); } }