package de.venjinx.jme3;
import java.util.HashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import de.venjinx.core.VoxelChunk;
import de.venjinx.core.VoxelObject;
import de.venjinx.core.VoxelWorld.VoxelMode;
import de.venjinx.jme3.scenegraph.ScenegraphNode;
public class VoxelObjectNode extends ScenegraphNode {
private VoxelObject voxelObject;
private int chunkCount = 0;
private VoxelChunkNode[][][] chunks;
private Material material;
private ScenegraphNode geometryNode = new ScenegraphNode("VoxelGeometryNode");
private Vector3f currentRefPoint = new Vector3f();
static ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1);
private HashMap<VoxelChunkNode, Future<VoxelChunkNode>> futureChunks = new HashMap<>();
public VoxelObjectNode(float[][][] voxelData) {
this(new VoxelObject(voxelData));
}
private VoxelObjectNode(VoxelObject vObject) {
super("VoxelObjectNode");
attachChild(geometryNode);
VoxelChunk[][][] voChunks = vObject.getChunks();
chunkCount = vObject.getChunkCount();
chunks = new VoxelChunkNode[chunkCount][chunkCount][chunkCount];
for (int x = 0; x < chunkCount; x++)
for (int y = 0; y < chunkCount; y++)
for (int z = 0; z < chunkCount; z++) {
chunks[x][y][z] = new VoxelChunkNode(voChunks[x][y][z]);
chunks[x][y][z].setMaterial(material);
geometryNode.attachChild(chunks[x][y][z]);
}
voxelObject = vObject;
}
public void update(Vector3f refPoint) {
currentRefPoint.set(refPoint);
voxelObject.update(refPoint.x, refPoint.y, refPoint.z);
long t = System.currentTimeMillis();
updateChunks();
// System.out.println("update object " + (System.currentTimeMillis() -
// t) + "ms");
}
private void updateChunks() {
VoxelChunkNode chunk;
Future<VoxelChunkNode> futureChunk;
for (int x = 0; x < chunkCount; x++)
for (int y = 0; y < chunkCount; y++)
for (int z = 0; z < chunkCount; z++) {
chunk = chunks[x][y][z];
if (chunk.needsGeneration()) {
if (!futureChunks.containsKey(chunk))
futureChunks.put(chunk, threadPool.submit(chunk));
} else {
futureChunk = futureChunks.get(chunk);
if ((futureChunk != null) && futureChunk.isDone()) {
futureChunks.remove(chunk);
if (!futureChunk.isCancelled())
chunk.switchGeometries();
}
}
}
}
public void setMode(VoxelMode mode) {
voxelObject.setMode(mode);
}
public void showChunkLODs() {
for (int x = 0; x < chunkCount; x++)
for (int y = 0; y < chunkCount; y++)
for (int z = 0; z < chunkCount; z++)
chunks[x][y][z].showLOD();
setMaterial(material);
}
public void showChunkBounds() {
for (int x = 0; x < chunkCount; x++)
for (int y = 0; y < chunkCount; y++)
for (int z = 0; z < chunkCount; z++)
chunks[x][y][z].showBound();
}
@Override
public void setMaterial(Material mat) {
material = mat;
super.setMaterial(mat);
}
public Material getMaterial() {
return material;
}
public VoxelObject getVoxelObject() {
return voxelObject;
}
public float[][][] getData() {
return voxelObject.getData();
}
public VoxelChunkNode[][][] getChunks() {
return chunks;
}
public int getChunkCount() {
return voxelObject.getChunkCount();
}
}