little general refactor
parent
be8cb056d3
commit
daf419ed40
|
@ -1,10 +1,8 @@
|
|||
package com.emamaker.voxeltest.intervaltrees;
|
||||
|
||||
import com.emamaker.voxeltest.intervaltrees.data.IntervalMap;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFillingCurve;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.WorldManager;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.blocks.Blocks;
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
|
@ -35,7 +33,7 @@ public class Voxel extends SimpleApplication {
|
|||
getCamera().lookAt(new Vector3f(Config.CHUNK_SIZE,Config.CHUNK_SIZE, Config.CHUNK_SIZE), Vector3f.UNIT_Y);
|
||||
|
||||
pos.set(this.getCamera().getLocation());
|
||||
SpaceFilling.initLUT();
|
||||
SpaceFillingCurve.initLUT();
|
||||
worldManager.initWorld();
|
||||
// worldManager.benchmark();
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.data;
|
||||
|
||||
/* When visualizing as a 1D array, high indicates the last index with a valid position (es. if there are 10 values), the interval will be (0,9) */
|
||||
|
||||
public class Interval {
|
||||
int low, high;
|
||||
|
||||
public Interval() {
|
||||
set(0, 0);
|
||||
}
|
||||
|
||||
|
||||
public Interval(int low_, int high_) {
|
||||
set(low_, high_);
|
||||
}
|
||||
|
||||
public void set(int low_, int high_) {
|
||||
this.low = low_;
|
||||
this.high = high_;
|
||||
}
|
||||
|
||||
public int getLow(){
|
||||
return low;
|
||||
}
|
||||
|
||||
public int getHigh(){
|
||||
return high;
|
||||
}
|
||||
public boolean isValid() {
|
||||
return this.low < this.high;
|
||||
}
|
||||
|
||||
// return if is contained in another interval
|
||||
public boolean contains(Interval i) {
|
||||
return this.low <= i.low && i.high <= this.high;
|
||||
}
|
||||
|
||||
// if contains another interval
|
||||
public boolean isContainedBy(Interval i) {
|
||||
return i.contains(this);
|
||||
}
|
||||
|
||||
public boolean fullyLeftOf(Interval i) {
|
||||
return this.high <= i.low;
|
||||
}
|
||||
|
||||
public boolean fullyRightOf(Interval i) {
|
||||
return this.low >= i.high;
|
||||
}
|
||||
|
||||
public boolean partiallyContainsLeft(Interval i) {
|
||||
return i.low < this.low && i.high >= this.low && i.high < this.high;
|
||||
}
|
||||
|
||||
public boolean partiallyContainsRight(Interval i) {
|
||||
return this.high >= i.low && this.low < i.low && this.high < i.high;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + low + ", " + high + ")";
|
||||
}
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class IntervalTree<V> {
|
||||
|
||||
TreeNode root = null;
|
||||
int size = 0;
|
||||
|
||||
public void insertValue(V value, Interval i) {
|
||||
root = insertNode(root, new TreeNode(i, value, null, null));
|
||||
// if (isEmpty()) {
|
||||
// root = new TreeNode(i, value, null, null);
|
||||
// size++;
|
||||
// } else
|
||||
// insertValue(root, value, i);
|
||||
}
|
||||
|
||||
public TreeNode getRoot() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
// For what we're doing, when we add new values that (partially) overlap old
|
||||
// ones, we can't have the old ones laying around, so intervals need to be
|
||||
// readjusted accordingly
|
||||
public TreeNode insertNode(TreeNode currentNode, TreeNode newNode) {
|
||||
if (!newNode.interval.isValid()) return null;
|
||||
if (currentNode == null) return newNode;
|
||||
|
||||
// System.out.println(currentNode.interval.toString() +", "+
|
||||
// newNode.interval.toString());
|
||||
|
||||
if (newNode.interval.fullyLeftOf(currentNode.interval)) {
|
||||
currentNode.setLeft(insertNode(currentNode.left, newNode));
|
||||
return currentNode;
|
||||
} else if (newNode.interval.fullyRightOf(currentNode.interval)) {
|
||||
currentNode.setRight(insertNode(currentNode.right, newNode));
|
||||
return currentNode;
|
||||
} else if (newNode.interval.contains(currentNode.interval)) {
|
||||
// check is they carry the same value
|
||||
if (newNode.value.equals(currentNode.value)) {
|
||||
currentNode.interval = newNode.interval;
|
||||
} else {
|
||||
TreeNode newLeftNode = new TreeNode(new Interval(newNode.interval.low, currentNode.interval.low), newNode.value, currentNode.left, null);
|
||||
|
||||
newNode.setInterval(currentNode.interval.high, newNode.interval.high);
|
||||
newNode.setRight(currentNode.right);
|
||||
|
||||
// Important! otherwhise already existing nodes will node by
|
||||
// replaced
|
||||
currentNode.value = newNode.value;
|
||||
|
||||
currentNode.setLeft(newLeftNode);
|
||||
currentNode.setRight(newNode);
|
||||
}
|
||||
|
||||
constrainIntervals(currentNode, currentNode.interval);
|
||||
return currentNode;
|
||||
|
||||
} else if (newNode.interval.isContainedBy(currentNode.interval)) {
|
||||
|
||||
if (newNode.value.equals(currentNode.value)) return currentNode;
|
||||
|
||||
if (currentNode.interval.low < newNode.interval.low)
|
||||
newNode.setLeft(new TreeNode(new Interval(currentNode.interval.low, newNode.interval.low), currentNode.value, currentNode.left, null));
|
||||
else newNode.setLeft(null);
|
||||
|
||||
if (newNode.interval.high < currentNode.interval.high)
|
||||
newNode.setRight(new TreeNode(new Interval(newNode.interval.high, currentNode.interval.high), currentNode.value, null, currentNode.right));
|
||||
else newNode.setRight(null);
|
||||
|
||||
return newNode;
|
||||
|
||||
} else if (newNode.interval.partiallyContainsLeft(currentNode.interval)) {
|
||||
currentNode.setInterval(currentNode.interval.low, newNode.interval.low);
|
||||
|
||||
newNode.setLeft(currentNode);
|
||||
constrainIntervals(currentNode, currentNode.interval);
|
||||
|
||||
return newNode;
|
||||
} else if (newNode.interval.partiallyContainsRight(currentNode.interval)) {
|
||||
currentNode.setInterval(newNode.interval.high, currentNode.interval.high);
|
||||
|
||||
newNode.setRight(currentNode);
|
||||
constrainIntervals(currentNode, currentNode.interval);
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
System.out.println("How did we get here?");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the value from n to n+1
|
||||
public V getSingleValue(int n) {
|
||||
return getValues(new Interval(n, n + 1)).get(0);
|
||||
}
|
||||
|
||||
public ArrayList<V> getValues(Interval interval) {
|
||||
ArrayList<V> values = new ArrayList<>();
|
||||
if (root != null && interval != null)
|
||||
getValues(interval, root, values);
|
||||
return values;
|
||||
}
|
||||
|
||||
private void getValues(Interval interval, TreeNode start, ArrayList<V> results) {
|
||||
System.out.println(interval.toString() + ", " + start.toString() + ", " + Arrays.toString(results.toArray()));
|
||||
|
||||
if (interval.fullyLeftOf(start.interval) && start.left != null)
|
||||
getValues(interval, start.left, results);
|
||||
else if (interval.fullyRightOf(start.interval) && start.right != null)
|
||||
getValues(interval, start.right, results);
|
||||
else if (interval.isContainedBy(start.interval))
|
||||
results.add(start.value); // base case
|
||||
else if (interval.contains(start.interval)) {
|
||||
results.add(start.value);
|
||||
Interval intLeft = new Interval(interval.low, start.interval.low);
|
||||
Interval intRight = new Interval(interval.high, start.interval.high);
|
||||
if (start.left != null && intLeft.isValid())
|
||||
getValues(intLeft, start.left, results);
|
||||
if (start.right != null && intRight.isValid())
|
||||
getValues(intRight, start.right, results);
|
||||
} else if (interval.partiallyContainsLeft(start.interval)) {
|
||||
results.add(start.value);
|
||||
Interval newInt = new Interval(start.interval.high, interval.high);
|
||||
if (start.right != null && newInt.isValid())
|
||||
getValues(newInt, start.right, results);
|
||||
} else if (interval.partiallyContainsRight(start.interval)) {
|
||||
results.add(start.value);
|
||||
Interval newInt = new Interval(interval.low, start.interval.low);
|
||||
if (start.left != null && newInt.isValid())
|
||||
getValues(newInt, start.left, results);
|
||||
}
|
||||
}
|
||||
|
||||
public TreeNode constrainIntervals(TreeNode start, Interval i) {
|
||||
if (start == null)
|
||||
return null;
|
||||
|
||||
start.interval.high = Math.min(start.interval.high, i.high);
|
||||
start.interval.low = Math.max(start.interval.low, i.low);
|
||||
|
||||
if (!start.interval.isValid())
|
||||
return null;
|
||||
|
||||
if (start.left != null)
|
||||
start.setLeft(constrainIntervals(start.left, new Interval(start.left.interval.low, start.interval.low)));
|
||||
if (start.right != null)
|
||||
start.setRight(
|
||||
constrainIntervals(start.right, new Interval(start.interval.high, start.right.interval.high)));
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
public void print() {
|
||||
System.out.println("================");
|
||||
print(root, 0);
|
||||
System.out.println("================");
|
||||
}
|
||||
|
||||
private void print(TreeNode tree, int level) {
|
||||
for (int i = 0; i < level; i++)
|
||||
System.out.print("\t");
|
||||
if (level != 0)
|
||||
System.out.print("|");
|
||||
for (int i = 0; i < level * 4; i++)
|
||||
System.out.print("-");
|
||||
|
||||
if (tree == null)
|
||||
System.out.println("NULL");
|
||||
else {
|
||||
System.out.println(tree.interval.toString() + ": " + tree.value);
|
||||
print(tree.left, level + 1);
|
||||
print(tree.right, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
public class TreeNode {
|
||||
|
||||
V value;
|
||||
Interval interval;
|
||||
TreeNode left, right;
|
||||
|
||||
public TreeNode(Interval interval_, V value_, TreeNode left_, TreeNode right_) {
|
||||
this.setInterval(interval_);
|
||||
this.setValue(value_);
|
||||
this.setLeft(left_);
|
||||
this.setRight(right_);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.interval.toString() + ": " + this.value.toString();
|
||||
}
|
||||
|
||||
public void setInterval(int low_, int high_) {
|
||||
this.interval.set(low_, high_);
|
||||
}
|
||||
|
||||
public void setInterval(Interval i) {
|
||||
this.interval = i;
|
||||
}
|
||||
|
||||
public Interval getInterval() {
|
||||
return this.interval;
|
||||
}
|
||||
|
||||
public void setValue(V value_) {
|
||||
this.value = value_;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setLeft(TreeNode left_) {
|
||||
this.left = left_;
|
||||
}
|
||||
|
||||
public void setRight(TreeNode right_) {
|
||||
this.right = right_;
|
||||
}
|
||||
|
||||
public TreeNode getLeft() {
|
||||
return this.left;
|
||||
}
|
||||
|
||||
public TreeNode getRight() {
|
||||
return this.right;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.utils;
|
||||
|
||||
public class SpaceFilling {
|
||||
public class SpaceFillingCurve {
|
||||
// http://and-what-happened.blogspot.com/2011/08/fast-2d-and-3d-hilbert-curves-and.html
|
||||
public static int[][][] MORTON_XYZ_ENCODE;
|
||||
public static short[][] MORTON_XYZ_DECODE;
|
|
@ -1,16 +1,14 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.world;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
import com.emamaker.voxeltest.intervaltrees.Voxel;
|
||||
import com.emamaker.voxeltest.intervaltrees.renderer.ChunkRenderer;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.chunk.ChunkGenerator;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.chunk.ChunkMesher;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFillingCurve;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Utils;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.chunk.Chunk;
|
||||
import com.jme3.scene.Node;
|
||||
|
||||
public class WorldManager {
|
||||
|
@ -19,7 +17,8 @@ public class WorldManager {
|
|||
|
||||
public int camx, camy, camz;
|
||||
|
||||
ChunkRenderer chunkRenderer = new ChunkRenderer();
|
||||
ChunkMesher chunkMesher = new ChunkMesher();
|
||||
ChunkGenerator chunkGenerator = new ChunkGenerator();
|
||||
|
||||
Node worldNode = new Node();
|
||||
|
||||
|
@ -34,32 +33,30 @@ public class WorldManager {
|
|||
|
||||
int chunkX, chunkY, chunkZ;
|
||||
int index;
|
||||
public boolean generated = false, meshed = false;
|
||||
public boolean generated = false, meshed = false, worldGenerated = false;
|
||||
|
||||
public void update() {
|
||||
camx = (int) (game.pos.getX());
|
||||
camy = (int) (game.pos.getY());
|
||||
camz = (int) (game.pos.getZ());
|
||||
|
||||
// // clamp to "chunk" coordinates
|
||||
// // The chunk with origin at x,y,z in chunk coords actually has the origin at
|
||||
// clamp to "chunk" coordinates
|
||||
// The chunk with origin at x,y,z in chunk coords actually has the origin at
|
||||
// x*chunksize, y*chunksize, z*chunksize in world coords
|
||||
chunkX = (int) (camx / Config.CHUNK_LENGTH);
|
||||
chunkY = (int) (camy / Config.CHUNK_LENGTH);
|
||||
chunkZ = (int) (camz / Config.CHUNK_LENGTH);
|
||||
|
||||
// System.out.println("camera at" + game.pos + new Vector3f(chunkX, chunkY,
|
||||
// chunkZ));
|
||||
|
||||
for (int i = Math.max(0, chunkX - Config.RENDER_DISTANCE); i < chunkX + Config.RENDER_DISTANCE; i++) {
|
||||
for (int j = Math.max(0, chunkY - Config.RENDER_DISTANCE); j < chunkY + Config.RENDER_DISTANCE; j++) {
|
||||
// for (int j = Math.max(0,chunkY - Config.RENDER_DISTANCE); j < chunkY +
|
||||
// Config.RENDER_DISTANCE; j++) {
|
||||
for (int k = Math.max(0, chunkZ - Config.RENDER_DISTANCE); k < chunkZ + Config.RENDER_DISTANCE; k++) {
|
||||
if(!Utils.withinDistance(chunkX, chunkY, chunkZ, i,j,k,Config.RENDER_DISTANCE)) continue;
|
||||
|
||||
index = SpaceFilling.Morton_3D_Encode_10bit((short)i, (short)j, (short)k);
|
||||
if (!chunks.containsKey(index)) chunks.put(index, new Chunk(i,j,k));
|
||||
index = SpaceFillingCurve.Morton_3D_Encode_10bit((short)i, (short)j, (short)k);
|
||||
if (!chunks.containsKey(index)) {
|
||||
chunks.put(index, new Chunk(i,j,k));
|
||||
worldGenerated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,20 +65,21 @@ public class WorldManager {
|
|||
meshed = false;
|
||||
for(Chunk c : chunks.values()){
|
||||
if(!generated && !c.bgetState(Chunk.CHUNK_STATE_GENERATED)) {
|
||||
c.arrayGenerateCorner();
|
||||
chunkGenerator.arrayGenerateCorner(c);
|
||||
c.setState(Chunk.CHUNK_STATE_GENERATED, true);
|
||||
generated = true;
|
||||
}
|
||||
if(!meshed && c.bgetState(Chunk.CHUNK_STATE_GENERATED)&& !c.bgetState(Chunk.CHUNK_STATE_MESHED)) {
|
||||
chunkRenderer.greedyMeshing(this, c);
|
||||
chunkMesher.greedyMeshing(this, c);
|
||||
c.setState(Chunk.CHUNK_STATE_MESHED, true);
|
||||
meshed = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(!generated && ! meshed) System.out.println("Finished world generation");
|
||||
if(!generated && !meshed && !worldGenerated){
|
||||
worldGenerated = true;
|
||||
System.out.println("Finished world generation");
|
||||
}
|
||||
|
||||
}
|
||||
public void render(){
|
||||
|
@ -90,18 +88,15 @@ public class WorldManager {
|
|||
game.getRootNode().attachChild(c.chunkNode);
|
||||
c.setState(Chunk.CHUNK_STATE_LOADED, true);
|
||||
}
|
||||
if(!Utils.withinDistance(chunkX, chunkY, chunkZ, (int)c.posx, (int)c.posy, (int)c.posz, Config.RENDER_DISTANCE)){
|
||||
if(!Utils.withinDistance(chunkX, chunkY, chunkZ, c.posx, c.posy, c.posz, Config.RENDER_DISTANCE)){
|
||||
c.chunkNode.removeFromParent();
|
||||
chunks.remove(SpaceFilling.Morton_3D_Encode_10bit((short)c.posx, (short)c.posy, (short)c.posz));
|
||||
chunks.remove(SpaceFillingCurve.Morton_3D_Encode_10bit((short)c.posx, (short)c.posy, (short)c.posz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean chunkInCameraLimits(Chunk c) {
|
||||
int vx = (int) c.posx;
|
||||
int vy = (int) c.posy;
|
||||
int vz = (int) c.posz;
|
||||
return vx >= Math.min(0, chunkX - Config.RENDER_DISTANCE ) && vx < Math.min(0, chunkX + Config.RENDER_DISTANCE) && vy >= chunkY - Config.RENDER_DISTANCE && vy < Math.min(0, chunkY + Config.RENDER_DISTANCE) && vz >= chunkZ - Config.RENDER_DISTANCE && vz < Math.min(0, chunkZ + Config.RENDER_DISTANCE);
|
||||
return c.posx >= Math.min(0, chunkX - Config.RENDER_DISTANCE ) && c.posx < Math.min(0, chunkX + Config.RENDER_DISTANCE) && c.posy >= chunkY - Config.RENDER_DISTANCE && c.posy < Math.min(0, chunkY + Config.RENDER_DISTANCE) && c.posz >= chunkZ - Config.RENDER_DISTANCE && c.posz < Math.min(0, chunkZ + Config.RENDER_DISTANCE);
|
||||
}
|
||||
|
||||
public void benchmark(){
|
||||
|
@ -109,8 +104,8 @@ public class WorldManager {
|
|||
for(int j = 0; j < Config.RENDER_DISTANCE*2; j++)
|
||||
for(int k = 0; k < Config.RENDER_DISTANCE*2; k++){
|
||||
Chunk c = new Chunk(i,j,k);
|
||||
c.arrayGenerateCorner();
|
||||
chunkRenderer.greedyMeshing(this, c);
|
||||
chunkGenerator.arrayGenerateCorner(c);
|
||||
chunkMesher.greedyMeshing(this, c);
|
||||
game.getRootNode().attachChild(c.chunkNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.world;
|
||||
package com.emamaker.voxeltest.intervaltrees.world.chunk;
|
||||
|
||||
import com.emamaker.voxeltest.intervaltrees.data.IntervalMap;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Utils;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.blocks.Blocks;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
|
||||
public class Chunk {
|
||||
|
@ -19,6 +17,7 @@ public class Chunk {
|
|||
public static byte CHUNK_STATE_GENERATED = 1;
|
||||
public static byte CHUNK_STATE_MESHED = 2;
|
||||
public static byte CHUNK_STATE_LOADED = 4;
|
||||
|
||||
public Chunk() {
|
||||
this(0,0,0);
|
||||
}
|
||||
|
@ -30,9 +29,6 @@ public class Chunk {
|
|||
chunkNode.setLocalTranslation(posx, posy, posz);
|
||||
chunkNode.setLocalTranslation(chunkNode.getLocalTranslation().mult(Config.CHUNK_SIZE).mult(Config.VOXEL_SIZE));
|
||||
|
||||
// I still have to decided if this is necessary. With an empty tree this
|
||||
// takes O(1)
|
||||
//blocks.insertTerminator(Config.CHUNK_3DCOORD_MAX_INDEX);
|
||||
blocks.insert(0, Config.CHUNK_3DCOORD_MAX_INDEX, Blocks.AIR);
|
||||
}
|
||||
|
||||
|
@ -56,8 +52,7 @@ public class Chunk {
|
|||
}
|
||||
|
||||
/*
|
||||
* Set blocks. Interval to be intended in the same way as in interval tree
|
||||
* (flatten 1d index of 3d coords)
|
||||
* Set blocks. Interval to be intended in the same way as in interval maps
|
||||
*/
|
||||
public void setBlocks(Blocks block, int intLow, int intHigh) {
|
||||
this.blocks.insert( Math.max(0,intLow), Math.min(Config.CHUNK_3DCOORD_MAX_INDEX+1, intHigh),block);
|
||||
|
@ -67,68 +62,6 @@ public class Chunk {
|
|||
return blocks.valueAtKey(Chunk.coord3DTo1D(x, y, z));
|
||||
}
|
||||
|
||||
public void generatePlane() {
|
||||
// blocks.print();
|
||||
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
this.setBlocks(Blocks.STONE, coord3DTo1D(0, 0, i), coord3DTo1D(Config.CHUNK_SIZE - 1, 0, i));
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
this.setBlocks(Blocks.DIRT, coord3DTo1D(0, 1, i), coord3DTo1D(Config.CHUNK_SIZE - 1, 1, i));
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
this.setBlocks(Blocks.GRASS, coord3DTo1D(0, 2, i), coord3DTo1D(Config.CHUNK_SIZE - 1, 2, i));
|
||||
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
this.setBlocks(Blocks.STONE, coord3DTo1D(0, 3, i), coord3DTo1D(Config.CHUNK_SIZE - 1, 3, i));
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
this.setBlocks(Blocks.DIRT, coord3DTo1D(0, 4, i), coord3DTo1D(Config.CHUNK_SIZE - 1, 4, i));
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++)
|
||||
this.setBlocks(Blocks.GRASS, coord3DTo1D(0, 5, i), coord3DTo1D(Config.CHUNK_SIZE - 1, 5, i));
|
||||
}
|
||||
|
||||
public void generateCube() {
|
||||
this.setBlocks(Blocks.STONE, 0,
|
||||
Config.CHUNK_3DCOORD_MAX_INDEX);
|
||||
}
|
||||
|
||||
public void generateStair() {
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++) {
|
||||
for (int j = 0; j < Config.CHUNK_SIZE; j++) {
|
||||
this.setBlocks(j < Config.CHUNK_SIZE - i - 1 ? Blocks.STONE : Blocks.GRASS, coord3DTo1D(0, i, j),
|
||||
coord3DTo1D(Config.CHUNK_SIZE - 1, i, j));
|
||||
}
|
||||
}
|
||||
|
||||
this.setBlocks(Blocks.DIRT, Chunk.coord3DTo1D(0, 0, 0), Chunk.coord3DTo1D(2, 0, 0));
|
||||
this.setBlocks(Blocks.DIRT, Chunk.coord3DTo1D(1, 0, 2), Chunk.coord3DTo1D(2, 0, 2));
|
||||
}
|
||||
|
||||
public void arrayGenerateCorner() {
|
||||
Blocks[] array = new Blocks[Config.CHUNK_3DCOORD_MAX_INDEX + 1];
|
||||
|
||||
int dist, hilbert;
|
||||
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++) {
|
||||
for (int j = 0; j < Config.CHUNK_SIZE; j++) {
|
||||
for (int k = 0; k < Config.CHUNK_SIZE; k++) {
|
||||
// Distance from 0,0,0
|
||||
dist = (int) Math.sqrt((i * i) + (j * j) + (k * k));
|
||||
hilbert = SpaceFilling.HILBERT_XYZ_ENCODE[i][j][k];
|
||||
if (dist <= (int) (Config.CHUNK_SIZE / 3))
|
||||
array[hilbert] = Blocks.STONE;
|
||||
else if (dist > (int) (Config.CHUNK_SIZE / 3) && dist <= (int) (2 * Config.CHUNK_SIZE / 3))
|
||||
array[hilbert] = Blocks.DIRT;
|
||||
else if (dist > (int) (2 * Config.CHUNK_SIZE / 3) && dist <= (int) (Config.CHUNK_SIZE))
|
||||
array[hilbert] = Blocks.GRASS;
|
||||
else
|
||||
array[hilbert] = Blocks.AIR;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.treeFrom1DArray(array);
|
||||
}
|
||||
|
||||
public Blocks[] treeTo1DArray() {
|
||||
// System.out.println(Config.CHUNK_3DCOORD_MAX_INDEX);
|
||||
Blocks[] result = new Blocks[Config.CHUNK_3DCOORD_MAX_INDEX + 1];
|
|
@ -0,0 +1,41 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.world.chunk;
|
||||
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFillingCurve;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.blocks.Blocks;
|
||||
|
||||
public class ChunkGenerator {
|
||||
|
||||
public void generateCube(Chunk c) {
|
||||
c.setBlocks(Blocks.STONE, 0,
|
||||
Config.CHUNK_3DCOORD_MAX_INDEX);
|
||||
}
|
||||
|
||||
public void arrayGenerateCorner(Chunk c) {
|
||||
Blocks[] array = new Blocks[Config.CHUNK_3DCOORD_MAX_INDEX + 1];
|
||||
|
||||
int dist, hilbert;
|
||||
|
||||
for (int i = 0; i < Config.CHUNK_SIZE; i++) {
|
||||
for (int j = 0; j < Config.CHUNK_SIZE; j++) {
|
||||
for (int k = 0; k < Config.CHUNK_SIZE; k++) {
|
||||
// Distance from 0,0,0
|
||||
dist = (int) Math.sqrt((i * i) + (j * j) + (k * k));
|
||||
hilbert = SpaceFillingCurve.HILBERT_XYZ_ENCODE[i][j][k];
|
||||
if (dist <= (int) (Config.CHUNK_SIZE / 3))
|
||||
array[hilbert] = Blocks.STONE;
|
||||
else if (dist > (int) (Config.CHUNK_SIZE / 3) && dist <= (int) (2 * Config.CHUNK_SIZE / 3))
|
||||
array[hilbert] = Blocks.DIRT;
|
||||
else if (dist > (int) (2 * Config.CHUNK_SIZE / 3) && dist <= (int) (Config.CHUNK_SIZE))
|
||||
array[hilbert] = Blocks.GRASS;
|
||||
else
|
||||
array[hilbert] = Blocks.AIR;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.treeFrom1DArray(array);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
package com.emamaker.voxeltest.intervaltrees.renderer;
|
||||
package com.emamaker.voxeltest.intervaltrees.world.chunk;
|
||||
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Config;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFilling;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.Utils;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.Chunk;
|
||||
import com.emamaker.voxeltest.intervaltrees.utils.SpaceFillingCurve;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.WorldManager;
|
||||
import com.emamaker.voxeltest.intervaltrees.world.blocks.Blocks;
|
||||
import com.jme3.material.Material;
|
||||
|
@ -17,7 +15,7 @@ import com.jme3.util.BufferUtils;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ChunkRenderer {
|
||||
public class ChunkMesher {
|
||||
|
||||
Blocks[] blocks;
|
||||
public void stupidArrayMeshing(WorldManager mgr, Chunk chunk) {
|
||||
|
@ -86,8 +84,6 @@ public class ChunkRenderer {
|
|||
short cIndex = 0;
|
||||
|
||||
public void greedyMeshing(WorldManager mgr, Chunk chunk) {
|
||||
long begin = System.nanoTime();
|
||||
|
||||
vIndex = 0;
|
||||
iIndex = 0;
|
||||
cIndex = 0;
|
||||
|
@ -129,9 +125,9 @@ public class ChunkRenderer {
|
|||
|
||||
for (x[v] = 0; x[v] < Config.CHUNK_SIZE; x[v]++) {
|
||||
for (x[u] = 0; x[u] < Config.CHUNK_SIZE; x[u]++) {
|
||||
Blocks b1 = (x[dim] >= 0) ? blocks[SpaceFilling.HILBERT_XYZ_ENCODE[x[0]][x[1]][x[2]]] : null;
|
||||
Blocks b1 = (x[dim] >= 0) ? blocks[SpaceFillingCurve.HILBERT_XYZ_ENCODE[x[0]][x[1]][x[2]]] : null;
|
||||
Blocks b2 = (x[dim] < Config.CHUNK_SIZE - 1)
|
||||
? blocks[SpaceFilling.HILBERT_XYZ_ENCODE[x[0] + q[0]][x[1] + q[1]][x[2]+q[2]]]
|
||||
? blocks[SpaceFillingCurve.HILBERT_XYZ_ENCODE[x[0] + q[0]][x[1] + q[1]][x[2]+q[2]]]
|
||||
: null;
|
||||
|
||||
// This is the original line taken from rob's code, readapted (replace voxelFace
|
||||
|
@ -229,9 +225,9 @@ public class ChunkRenderer {
|
|||
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.setBuffer(Type.Position, 3,
|
||||
BufferUtils.createFloatBuffer((Vector3f[]) Arrays.copyOf(vertices, vIndex)));
|
||||
mesh.setBuffer(Type.Color, 4, BufferUtils.createFloatBuffer((float[]) Arrays.copyOf(colors, cIndex)));
|
||||
mesh.setBuffer(Type.Index, 3, BufferUtils.createShortBuffer((short[]) Arrays.copyOf(indices, iIndex)));
|
||||
BufferUtils.createFloatBuffer(Arrays.copyOf(vertices, vIndex)));
|
||||
mesh.setBuffer(Type.Color, 4, BufferUtils.createFloatBuffer(Arrays.copyOf(colors, cIndex)));
|
||||
mesh.setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(Arrays.copyOf(indices, iIndex)));
|
||||
mesh.updateBound();
|
||||
|
||||
Geometry geo = new Geometry("ColoredMesh", mesh);
|
||||
|
@ -245,7 +241,6 @@ public class ChunkRenderer {
|
|||
geo.setMaterial(mat);
|
||||
chunk.chunkNode.attachChild(geo);
|
||||
}
|
||||
System.out.println("Greedy meshing of chunk took " + (System.nanoTime()-begin ) + " ns");
|
||||
}
|
||||
|
||||
final int VOXEL_SIZE = 1;
|
Loading…
Reference in New Issue