package de.venjinx.jme3;
import java.util.HashSet;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.bounding.BoundingSphere;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import de.venjinx.core.Vector3;
import de.venjinx.core.VoxelWorld;
import de.venjinx.core.VoxelWorld.VoxelMode;
import de.venjinx.jme3.scenegraph.ScenegraphNode;
import de.venjinx.util.CameraFrustum;
public class VoxelState extends AbstractAppState {
private static int maxLOD = 10;
private static float resolution = FastMath.pow(2, -10);
private static float extractThreshold = 0f;
private static float viewDistance = 0;
private static int maxChunkSize = 32;
private VoxelWorld world;
private SimpleApplication simpleApp;
private AssetManager am;
private RenderManager rm;
private Camera cam;
private Vector3f camPos;
private Vector3 refPoint;
private CameraFrustum camFrustum;
private BoundingSphere worldBound;
private ScenegraphNode voxelWorldNode;
private HashSet<VoxelObjectNode> worldObjects = new HashSet<>();
public VoxelState() {
voxelWorldNode = new ScenegraphNode("VoxelWorld");
world = new VoxelWorld();
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
if (app instanceof SimpleApplication)
simpleApp = (SimpleApplication) app;
simpleApp.getRootNode().attachChild(voxelWorldNode);
am = simpleApp.getAssetManager();
rm = simpleApp.getRenderManager();
cam = simpleApp.getCamera();
viewDistance = cam.getFrustumFar();
camPos = cam.getLocation();
world.setViewDistance(viewDistance);
camFrustum = new CameraFrustum(cam);
worldBound = new BoundingSphere(viewDistance * 1.1f, cam.getLocation());
}
@Override
public void update(float tpf) {
long t = System.currentTimeMillis();
for (VoxelObjectNode obj : worldObjects)
obj.update(camPos);
// System.out.println("update object " + (System.currentTimeMillis() -
// t) + "ms");
}
public VoxelWorld getVoxelWorld() {
return world;
}
public void addObject(VoxelObjectNode voxelObject) {
worldObjects.add(voxelObject);
voxelWorldNode.attachChild(voxelObject);
}
public BoundingSphere getCalcBound() {
return worldBound;
}
public static int maxLOD() {
return maxLOD;
}
public static float viewDistance() {
return viewDistance;
}
public static float[][][] loadFromHeightMap(AbstractHeightMap heightMap,
VoxelMode mode) {
float[][][] data = null;
int size = heightMap.getSize();
switch (mode) {
case LINE_2D:
case SURFACE_2D:
data = new float[size + 1][size + 1][size + 1];
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
data[x][y][z] = VoxelState.getVoxelValue(x, z, heightMap);
data[x][y][z] -= (y - 0) / (size / 2f);
data[x][y][z] = VoxelState.matchToResolution(data[x][y][z]);
}
break;
case LINE_3D:
break;
case SURFACE_3D:
break;
}
return data;
}
public static float getVoxelValue(float x, float z, AbstractHeightMap heightMap) {
float value = (heightMap.getInterpolatedHeight(x, z) / 255) - .03f;
value -= extractThreshold;
value = VoxelState.matchToResolution(value);
return value;
}
public static float matchToResolution(float value) {
value /= resolution;
value = Math.round(value);
value *= resolution;
return value;
}
@Override
public void cleanup() {
VoxelObjectNode.threadPool.shutdownNow();
world.stop();
}
// public static long generateVertexID(Vector3f vertex, int normalID) {
// long vertID;
// long x = (long) (vertex.x * FastMath.pow(10, maxLOD));
// long y = (long) (vertex.y * FastMath.pow(10, maxLOD));
// long z = (long) (vertex.z * FastMath.pow(10, maxLOD));
// vertID = ((x * zipKey * zipKey * 16) + (y * zipKey * 16) + (z * 16)) +
// normalID;
// return vertID;
// }
}