Renderer/src/main/java/electrosphere/game/client/cells/DrawCellManager.java
2021-08-07 18:00:19 -04:00

652 lines
24 KiB
Java

package electrosphere.game.client.cells;
import electrosphere.game.client.terrain.manager.ClientTerrainManager;
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
import electrosphere.game.client.world.ClientWorldData;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.WorldMessage;
import electrosphere.renderer.ShaderProgram;
import java.util.Arrays;
import java.util.HashMap;
import org.joml.Vector3f;
/**
*
* @author satellite
*/
public class DrawCellManager {
//the center of this cell manager's array in cell space
int cellX;
int cellY;
//the dimensions of the world that this cell manager can handles
int cellWidth;
int cellHeight;
//the width of a minicell in this manager
int miniCellWidth;
//all currently displaying mini cells
DrawCell[][] cells;
boolean[][] valid;
boolean[][] drawable;
boolean[][] updateable;
boolean[][] hasRequested;
boolean[][] needsPhysics;
boolean[][] hasPhysics;
ShaderProgram program;
int drawRadius = 5;
int drawStepdownInterval = 3;
int drawStepdownValue = 25;
int physicsRadius = 3;
int worldBoundDiscreteMin = 0;
int worldBoundDiscreteMax = 0;
//metadata about the game world
ClientWorldData clientWorldData;
//client terrain manager
ClientTerrainManager clientTerrainManager;
//ready to start updating?
boolean update = false;
public DrawCellManager(ClientWorldData clientWorldData, ClientTerrainManager clientTerrainManager, int discreteX, int discreteY){
this.clientWorldData = clientWorldData;
worldBoundDiscreteMax = (int)(this.clientWorldData.getWorldBoundMax().x / this.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
this.clientTerrainManager = clientTerrainManager;
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];
hasRequested = new boolean[drawRadius * 2 + 1][drawRadius * 2 + 1];
needsPhysics = new boolean[physicsRadius * 2 + 1][physicsRadius * 2 + 1];
hasPhysics = new boolean[physicsRadius * 2 + 1][physicsRadius * 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;
hasRequested[x][y] = false;
}
}
for(int x = 0; x < physicsRadius * 2 + 1; x++){
for(int y = 0; y < physicsRadius * 2 + 1; y++){
needsPhysics[x][y] = true;
hasPhysics[x][y] = false;
}
}
cellX = discreteX;
cellY = discreteY;
program = Globals.defaultMeshShader;
drawRadius = Globals.userSettings.getGraphicsPerformanceLODChunkRadius();
drawStepdownInterval = Globals.userSettings.getGameplayPhysicsCellRadius();
physicsRadius = Globals.userSettings.getGameplayPhysicsCellRadius();
update = true;
}
DrawCellManager(){
}
public int getCellX(){
return cellX;
}
public int getCellY(){
return cellY;
}
public void setCellX(int x){
cellX = x;
}
public void setCellY(int y){
cellY = y;
}
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 < clientWorldData.getWorldDiscreteSize() &&
currentCellY >= 0 &&
currentCellY < clientWorldData.getWorldDiscreteSize()
){
if(clientTerrainManager.containsHeightmapAtDiscretePoint(currentCellX, currentCellY)){
cells[targetX][targetY] = DrawCell.generateTerrainCell(
currentCellX,
currentCellY,
clientTerrainManager.getHeightmapAtPoint(currentCellX, currentCellY),
clientWorldData.getDynamicInterpolationRatio(),
program
);
valid[targetX][targetY] = true;
drawable[targetX][targetY] = false;
updateable[targetX][targetY] = false;
hasRequested[targetX][targetY] = false;
// if(Math.abs(physicsRadius + 1 - targetX) < physicsRadius && Math.abs(physicsRadius + 1 - targetY) < physicsRadius){
// needsPhysics[targetX][targetY] = true;
// }
} else {
if(hasRequested[targetX][targetY] == false){
//client should request macro values from server
Globals.clientConnection.queueOutgoingMessage(WorldMessage.constructRequestChunkMessage(currentCellX, currentCellY));
hasRequested[targetX][targetY] = true;
}
}
} else {
valid[targetX][targetY] = true;
drawable[targetX][targetY] = false;
updateable[targetX][targetY] = false;
hasRequested[targetX][targetY] = false;
}
}
}
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 < clientWorldData.getWorldDiscreteSize() &&
currentCellY >= 0 &&
currentCellY < clientWorldData.getWorldDiscreteSize()
){
//physics radius calculation
// if(Math.abs(physicsRadius + 1 - targetX) < physicsRadius && Math.abs(physicsRadius + 1 - targetY) < physicsRadius){
// needsPhysics[targetX][targetY] = true;
// }
//calculation for stride
int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius));//Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
int stride = Math.min(clientWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue));
while(clientWorldData.getDynamicInterpolationRatio() % stride != 0){
stride = stride + 1;
}
//make drawable entity
cells[targetX][targetY].generateDrawableEntity(stride);
}
drawable[targetX][targetY] = true;
}
}
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 < clientWorldData.getWorldDiscreteSize() &&
currentCellY >= 0 &&
currentCellY < clientWorldData.getWorldDiscreteSize()
){
// if(Math.abs(drawRadius + 1 - targetX) < physicsRadius && Math.abs(drawRadius + 1 - targetY) < physicsRadius){
// needsPhysics[targetX][targetY] = true;
// }
int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius)); //Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
int stride = Math.min(clientWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue));
while(clientWorldData.getDynamicInterpolationRatio() % stride != 0){
stride = stride + 1;
}
cells[targetX][targetY].generateDrawableEntity(stride);
}
updateable[targetX][targetY] = false;
drawable[targetX][targetY] = true;
}
}
public boolean containsInvalidCell(){
// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){
for(int x = 0;x < drawRadius * 2 + 1; x++){
for(int y = 0; y < drawRadius * 2 + 1; y++){
if(!valid[x][y]){
return true;
}
}
}
// } else if(DRAW_CELL_MANAGER_FLAG_GENERATE_ARENA){
// return cells[0][0] == null || cells[1][0] == null || cells[0][1] == null | cells[1][1] == null;
// }
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 boolean containsPhysicsNeedingCell(){
for(int x = 0; x < physicsRadius * 2 + 1; x++){
for(int y = 0; y < physicsRadius * 2 + 1; y++){
if(needsPhysics[x][y]){
return true;
}
}
}
return false;
}
public void addPhysicsToCell(){
int targetX = 0;
int targetY = 0;
boolean found = false;
for(int x = 0; x < physicsRadius * 2 + 1; x++){
targetX = x;
for(int y = 0; y < physicsRadius * 2 + 1; y++){
targetY = y;
// System.out.println(x + " <=>w " + y);
if(needsPhysics[x][y]){
found = true;
break;
}
}
if(found){
break;
}
}
if(found){
int currentCellX = cellX - physicsRadius + targetX;
int currentCellY = cellY - physicsRadius + targetY;
if(
currentCellX >= 0 &&
currentCellX < clientWorldData.getWorldDiscreteSize() &&
currentCellY >= 0 &&
currentCellY < clientWorldData.getWorldDiscreteSize()
){
// if(Math.abs(drawRadius + 1 - targetX) < physicsRadius && Math.abs(drawRadius + 1 - targetY) < physicsRadius){
// needsPhysics[targetX][targetY] = true;
// }
// int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius)); //Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
// int stride = Math.min(clientWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue));
// while(clientWorldData.getDynamicInterpolationRatio() % stride != 0){
// stride = stride + 1;
// }
// if(cells[targetX][targetY + drawRadius] != null){
// System.out.println(targetX + " - " + targetY);
cells[targetX + drawRadius - physicsRadius][targetY + drawRadius - physicsRadius].generatePhysics();
// } else {
// System.out.println("Current cell is null: " + currentCellX + " - " + currentCellY);
// }
}
needsPhysics[targetX][targetY] = false;
hasPhysics[targetX][targetY] = true;
}
}
public void shiftChunksNegX(){
//retire old graphics
for(int y = 0; y < drawRadius * 2 + 1; y++){
if(cells[drawRadius * 2][y] != null){
cells[drawRadius * 2][y].retireCell();
}
}
//shift draw array
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;
hasRequested[x][y] = hasRequested[x-1][y];
}
}
//invalidate edge of draw array
for(int y = 0; y < drawRadius * 2 + 1; y++){
valid[0][y] = false;
hasRequested[0][y] = false;
}
//retire physics of cells
for(int x = 0; x < physicsRadius * 2 + 1; x++){
if(hasPhysics[x][physicsRadius * 2]){
cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius].destroyPhysics();
}
}
//shift physics array
for(int x = physicsRadius * 2; x > 0; x--){
for(int y = 0; y < physicsRadius * 2 + 1; y++){
needsPhysics[x][y] = needsPhysics[x-1][y];
hasPhysics[x][y] = hasPhysics[x-1][y];
}
}
//invalidate edge of physics array
for(int y = 0; y < physicsRadius * 2 + 1; y++){
needsPhysics[0][y] = true;
hasPhysics[0][y] = false;
}
}
public void shiftChunksPosX(){
//retire old graphics
for(int y = 0; y < drawRadius * 2 + 1; y++){
if(cells[0][y] != null){
cells[0][y].retireCell();
}
}
//shift draw array
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;
hasRequested[x][y] = hasRequested[x+1][y];
}
}
//invalidate edge of draw array
for(int y = 0; y < drawRadius * 2 + 1; y++){
valid[drawRadius * 2][y] = false;
hasRequested[drawRadius * 2][y] = false;
}
//retire physics of cells
for(int x = 0; x < physicsRadius * 2 + 1; x++){
if(hasPhysics[x][physicsRadius * 2]){
cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius].destroyPhysics();
}
}
//shift physics array
for(int x = 0; x < physicsRadius * 2; x++){
for(int y = 0; y < physicsRadius * 2 + 1; y++){
needsPhysics[x][y] = needsPhysics[x+1][y];
hasPhysics[x][y] = hasPhysics[x+1][y];
}
}
//invalidate edge of physics array
for(int y = 0; y < physicsRadius * 2 + 1; y++){
needsPhysics[physicsRadius * 2][y] = true;
hasPhysics[physicsRadius * 2][y] = false;
}
}
public void shiftChunksNegY(){
//retire cells
for(int x = 0; x < drawRadius * 2 + 1; x++){
if(cells[x][drawRadius * 2] != null){
cells[x][drawRadius * 2].retireCell();
}
}
//shift draw array
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;
hasRequested[x][y] = hasRequested[x][y-1];
}
}
//invalidate edge of draw array
for(int x = 0; x < drawRadius * 2 + 1; x++){
valid[x][0] = false;
hasRequested[x][0] = false;
}
//retire physics of cells
for(int x = 0; x < physicsRadius * 2 + 1; x++){
if(hasPhysics[x][physicsRadius * 2]){
cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius].destroyPhysics();
}
}
//shift physics array
for(int x = 0; x < physicsRadius * 2 + 1; x++){
for(int y = physicsRadius * 2; y > 0; y--){
needsPhysics[x][y] = needsPhysics[x][y-1];
hasPhysics[x][y] = hasPhysics[x][y-1];
}
}
//invalidate edge of physics array
for(int x = 0; x < physicsRadius * 2 + 1; x++){
needsPhysics[x][0] = true;
hasPhysics[x][0] = false;
}
}
public void shiftChunksPosY(){
//retire old graphics
for(int x = 0; x < drawRadius * 2 + 1; x++){
if(cells[x][0] != null){
cells[x][0].retireCell();
}
}
//shift draw array
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;
hasRequested[x][y] = hasRequested[x][y+1];
}
}
//invalidate edge of draw array
for(int x = 0; x < drawRadius * 2 + 1; x++){
valid[x][drawRadius * 2] = false;
hasRequested[x][drawRadius * 2] = false;
}
//retire physics of cells
for(int x = 0; x < physicsRadius * 2 + 1; x++){
if(hasPhysics[x][0]){
cells[x + drawRadius - physicsRadius][0 + drawRadius - physicsRadius].destroyPhysics();
}
}
//shift physics array
for(int x = 0; x < physicsRadius * 2 + 1; x++){
for(int y = 0; y < physicsRadius * 2; y++){
needsPhysics[x][y] = needsPhysics[x][y+1];
hasPhysics[x][y] = hasPhysics[x][y+1];
}
}
//invalidate edge of physics array
for(int x = 0; x < physicsRadius * 2 + 1; x++){
needsPhysics[x][physicsRadius * 2] = true;
hasPhysics[x][physicsRadius * 2] = false;
}
}
public int transformRealSpaceToCellSpace(float input){
return (int)(input / clientWorldData.getDynamicInterpolationRatio());
}
public void invalidateAllCells(){
for(int x = 0; x < drawRadius * 2 + 1; x++){
for(int y = 0; y < drawRadius * 2 + 1; y++){
valid[x][y] = false;
}
}
}
public void calculateDeltas(Vector3f oldPosition, Vector3f newPosition){
// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){
if(transformRealSpaceToCellSpace(newPosition.x()) < transformRealSpaceToCellSpace(oldPosition.x())){
shiftChunksNegX();
setCellX(transformRealSpaceToCellSpace(newPosition.x()));
setCellY(transformRealSpaceToCellSpace(newPosition.z()));
} else if(transformRealSpaceToCellSpace(newPosition.x()) > transformRealSpaceToCellSpace(oldPosition.x())){
shiftChunksPosX();
setCellX(transformRealSpaceToCellSpace(newPosition.x()));
setCellY(transformRealSpaceToCellSpace(newPosition.z()));
}
if(transformRealSpaceToCellSpace(newPosition.z()) < transformRealSpaceToCellSpace(oldPosition.z())){
shiftChunksNegY();
setCellX(transformRealSpaceToCellSpace(newPosition.x()));
setCellY(transformRealSpaceToCellSpace(newPosition.z()));
} else if(transformRealSpaceToCellSpace(newPosition.z()) > transformRealSpaceToCellSpace(oldPosition.z())){
shiftChunksPosY();
setCellX(transformRealSpaceToCellSpace(newPosition.x()));
setCellY(transformRealSpaceToCellSpace(newPosition.z()));
}
// }
}
public void update(){
if(update){
// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){
if(containsInvalidCell()){
updateInvalidCell();
} else if(containsUndrawableCell()){
makeCellDrawable();
} else if(containsUpdateableCell()){
updateCellModel();
} else if(containsPhysicsNeedingCell()){
addPhysicsToCell();
}
}
// } else if(DRAW_CELL_MANAGER_FLAG_GENERATE_ARENA){
// if(cells[0][0] == null){
// int arenaChunkWidth = 100;
// cells[0][0] = new DrawCell(
// new float[arenaChunkWidth + 1][arenaChunkWidth + 1],
// arenaChunkWidth + 1,
// 0,
// 0,
// arenaChunkWidth,
// program
// );
// cells[0][0].generateDrawableEntity(1);
// } else if(cells[0][1] == null){
// int arenaChunkWidth = 100;
// cells[0][1] = new DrawCell(
// new float[arenaChunkWidth + 1][arenaChunkWidth + 1],
// arenaChunkWidth + 1,
// 0,
// 1,
// arenaChunkWidth,
// program
// );
// cells[0][1].generateDrawableEntity(1);
// } else if(cells[1][0] == null){
// int arenaChunkWidth = 100;
// cells[1][0] = new DrawCell(
// new float[arenaChunkWidth + 1][arenaChunkWidth + 1],
// arenaChunkWidth + 1,
// 1,
// 0,
// arenaChunkWidth,
// program
// );
// cells[1][0].generateDrawableEntity(1);
// } else if(cells[1][1] == null){
// int arenaChunkWidth = 100;
// cells[1][1] = new DrawCell(
// new float[arenaChunkWidth + 1][arenaChunkWidth + 1],
// arenaChunkWidth + 1,
// 1,
// 1,
// arenaChunkWidth,
// program
// );
// cells[1][1].generateDrawableEntity(1);
// }
// }
}
// public float getElevationAtRealPoint(float realPointX, float realPointY){
//// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){
// return terrainManager.getHeightAtPosition(realPointX, realPointY);
//// }
//// if(DRAW_CELL_MANAGER_FLAG_GENERATE_ARENA){
//// return 0;
//// }
//// return 0;
// }
public boolean canValidateCell(){
boolean rVal = false;
return rVal;
}
public boolean coordsInPhysicsSpace(int worldX, int worldY){
return worldX <= cellX + physicsRadius && worldX >= cellX - physicsRadius && worldY <= cellY + physicsRadius && worldY >= cellY - physicsRadius;
}
// public
}