package Hexel.chunk;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import Hexel.Engine;
import Hexel.blocks.types.BlockTransparent;
import Hexel.math.HexGeometry;
import Hexel.math.Vector2d;
import Hexel.math.Vector3i;
import Hexel.rendering.Camera;
import Hexel.rendering.GLChunk;
import Hexel.rendering.Renderer;
import Hexel.things.types.Thing;
public class ChunkVisibilityManager {
private Chunks chunks;
private Renderer renderer;
public Set<Vector3i> renderedChunks = Collections.newSetFromMap(new ConcurrentHashMap<Vector3i, Boolean>());
public Set<Vector3i> simulatedChunks = Collections.newSetFromMap(new ConcurrentHashMap<Vector3i, Boolean>());
public Set<Vector3i> distanceChunks = Collections.newSetFromMap(new ConcurrentHashMap<Vector3i, Boolean>());
public int renderDistance = 2*30;
private Engine engine;
private int lastLightLevel = 0;
public ChunkVisibilityManager(Engine engine, Chunks chunks, Renderer renderer) {
this.engine = engine;
this.chunks = chunks;
this.renderer = renderer;
}
public void updateVisibility(Camera camera) {
Vector2d pos = new Vector2d();
HexGeometry.cartesianToHex(camera.getCameraX(), camera.getCameraY(), pos);
int cx = (int) Math.floor(pos.x / 16.0);
int cy = (int) Math.floor(pos.y / 16.0);
int cz = (int) Math.floor(camera.getCameraZ() / 16.0);
ArrayList<Vector3i> points = new ArrayList<Vector3i>();
ArrayList<Vector3i> inRenderRange = new ArrayList<Vector3i>();
ArrayList<Vector3i> inSimRange = new ArrayList<Vector3i>();
ArrayList<Vector3i> inDistRange = new ArrayList<Vector3i>();
int lightLevel = (int) (BlockTransparent.MAX_LIGHT_LEVEL*engine.getAmbientLight());
boolean resetLights = lastLightLevel != lightLevel;
int distanceChunksRange = 8;
int renderedChunksRange = 4;
int simulatedChunksRange = 1;
for (int x = -distanceChunksRange; x <= distanceChunksRange; x++) {
for (int y = -distanceChunksRange; y <= distanceChunksRange; y++) {
for (int z = -distanceChunksRange; z <= distanceChunksRange; z++) {
int ncx = cx + x;
int ncy = cy + y;
int ncz = cz + z;
Vector3i cpos = new Vector3i(ncx, ncy, ncz);
boolean pInRenderRange = false;
if (x >= -renderedChunksRange && x <= renderedChunksRange){
if (y >= -renderedChunksRange && y <= renderedChunksRange){
if (z >= -renderedChunksRange && z <= renderedChunksRange){
pInRenderRange = true;
inRenderRange.add(cpos);
Chunk chunk = this.chunks.getChunk(cpos);
if (!chunk.needFirstSim && !chunk.fastMode){
if (!this.renderedChunks.contains(cpos)) {
points.add(cpos);
chunk.setDirty(false);
} else {
if (resetLights || chunk.isDirty()) {
chunk.setDirty(false);
points.add(cpos);
}
}
}
if (points.size() > 10) {
this.renderer.loadChunks(points);
this.renderedChunks.addAll(points);
points = new ArrayList<Vector3i>();
}
if (x >= -simulatedChunksRange && x <= simulatedChunksRange){
if (y >= -simulatedChunksRange && y <= simulatedChunksRange){
if (z >= -simulatedChunksRange && z <= simulatedChunksRange){
inSimRange.add(cpos);
this.simulatedChunks.add(cpos);
}
}
}
}
}
if (!pInRenderRange){
inDistRange.add(cpos);
}
}
}
}
}
this.renderer.loadChunks(points);
this.renderedChunks.addAll(points);
lastLightLevel = lightLevel;
HashMap<Vector3i, GLChunk> glChunkTable = this.renderer.getGLChunkTable();
for (Vector3i p : new HashSet<Vector3i>(glChunkTable.keySet())) {
if (!inRenderRange.contains(p)) {
this.renderer.unloadGLChunk(p);
}
}
Iterator<Vector3i> iter = this.renderedChunks.iterator();
ArrayList<Vector3i> toRemove = new ArrayList<Vector3i>();
while (iter.hasNext()) {
Vector3i position = iter.next();
if (!inRenderRange.contains(position) && !points.contains(position)) {
toRemove.add(position);
}
}
this.renderedChunks.removeAll(toRemove);
iter = this.simulatedChunks.iterator();
toRemove = new ArrayList<Vector3i>();
while (iter.hasNext()) {
Vector3i position = iter.next();
if (!inSimRange.contains(position)) {
toRemove.add(position);
}
}
this.simulatedChunks.removeAll(toRemove);
iter = this.distanceChunks.iterator();
toRemove = new ArrayList<Vector3i>();
while (iter.hasNext()) {
Vector3i position = iter.next();
if (!inDistRange.contains(position)) {
toRemove.add(position);
}
}
this.distanceChunks.removeAll(toRemove);
}
}