diff --git a/src/main/java/com/seibel/lod/objects/LevelContainer.java b/src/main/java/com/seibel/lod/objects/LevelContainer.java index a5f7417ad..f35de59b4 100644 --- a/src/main/java/com/seibel/lod/objects/LevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/LevelContainer.java @@ -5,12 +5,59 @@ import com.seibel.lod.util.LodUtil; public interface LevelContainer { - public static final char VERTICAL_DATA_DELIMITER = ','; - public static final char DATA_DELIMITER = ','; + public static final char VERTICAL_DATA_DELIMITER = '\t'; + public static final char DATA_DELIMITER = '\n'; - public boolean putData(long[] data, int posX, int posZ); + /**With this you can add data to the level container + * + * @param data actual data to add in a array of long format. + * @param detailLevel just to check that it's correct + * @param posX x position in the detail level + * @param posZ z position in the detail level + * @return true if correctly added, false otherwise + */ + public boolean addData(long[] data, int posX, int posZ); + + /**With this you can get data from the level container + * + * @param detailLevel just to check that it's correct + * @param posX x position in the detail level + * @param posZ z position in the detail level + * @return the data in long array format + */ public long[] getData(int posX, int posZ); - /**TODO could i use a static map from thread name to arrays to store these values?*/ - public long[] mergeData(long[][] dataArray, long[] newDataPoint, int[] indexes, long[] dataToCombine); + + /** + * @param detailLevel just to check that it's correct + * @param posX x position in the detail level + * @param posZ z position in the detail level + * @return true only if the data exist + */ + public boolean doesItExist(int posX, int posZ); + + /** + * @return return the deatilLevel of this level container + */ + public byte getDetailLevel(); + + /**This return a level container with detail level lower than the current level. + * The new level container may use information of this level. + * @return the new level container + */ + public LevelContainer expand(); + + /** + * + * @param lowerLevelContainer lower level where we extract the data + * @param detailLevel detail level to update + * @param posX x position in the detail level to update + * @param posZ z position in the detail level to update + */ + public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ); + + /** + * This will give the data to save in the file + * @return data as a String + */ public String toDataString(); } diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index 63794ce8e..66682ea8f 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -22,55 +22,42 @@ public class LodRegion private byte minDetailLevel; private static final byte POSSIBLE_LOD = 10; //private int numberOfPoints; - private DistanceGenerationMode generationMode; //For each of the following field the first slot is for the level of detail //Important: byte have a [-128, 127] range. When converting from or to int a 128 should be added or removed //If there is a bug with color then it's probably caused by this. //in the future other fields like transparency and light level could be added - private long[][][] data; + private LevelContainer[] dataContainer; public final int regionPosX; public final int regionPosZ; - public LodRegion(VerticalLevelContainer verticalLevelContainer, RegionPos regionPos, DistanceGenerationMode generationMode) + public LodRegion(RegionPos regionPos) { - this.generationMode = generationMode; + this.minDetailLevel = LodUtil.REGION_DETAIL_LEVEL; this.regionPosX = regionPos.x; this.regionPosZ = regionPos.z; - this.minDetailLevel = verticalLevelContainer.detailLevel; - - //Arrays of matrices - data = new long[POSSIBLE_LOD][][]; - - data[minDetailLevel] = verticalLevelContainer.data; - - //Initialize all the different matrices - for (byte lod = (byte) (minDetailLevel + 1); lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) - { - int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod); - data[lod] = new long[size][size]; - } - updateArea(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ); + dataContainer = new LevelContainer[POSSIBLE_LOD]; } - public LodRegion(byte minDetailLevel, RegionPos regionPos, DistanceGenerationMode generationMode) + public LodRegion(byte minDetailLevel, RegionPos regionPos, boolean twoDimension) { - this.generationMode = generationMode; this.minDetailLevel = minDetailLevel; this.regionPosX = regionPos.x; this.regionPosZ = regionPos.z; - data = new long[POSSIBLE_LOD][][]; + dataContainer = new LevelContainer[POSSIBLE_LOD]; //Initialize all the different matrices for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) { - int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod); - data[lod] = new long[size][size]; - + if(twoDimension){ + dataContainer[lod] = new SingleLevelContainer(lod); + }else{ + dataContainer[lod] = new VerticalLevelContainer(lod); + } } } @@ -80,7 +67,7 @@ public class LodRegion * @param dataPoint * @return */ - public boolean addData(byte detailLevel, int posX, int posZ, long dataPoint, boolean serverQuality) + public boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean serverQuality) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); @@ -91,7 +78,7 @@ public class LodRegion //if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++; //add the node data - this.data[detailLevel][posX][posZ] = dataPoint; + this.dataContainer[detailLevel].addData(dataPoint, posX, posZ); return true; } else { @@ -104,11 +91,11 @@ public class LodRegion * * @return the data at the relative pos and level */ - public long getData(byte detailLevel, int posX, int posZ) + public long[] getData(byte detailLevel, int posX, int posZ) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - return data[detailLevel][posX][posZ]; + return dataContainer[detailLevel].getData(posX, posZ); } /** @@ -288,63 +275,7 @@ public class LodRegion */ private void update(byte detailLevel, int posX, int posZ) { - int numberOfChildren = 0; - int numberOfVoidChildren = 0; - - int tempRed = 0; - int tempGreen = 0; - int tempBlue = 0; - int tempHeight = 0; - int tempDepth = 0; - int childPosX; - int childPosZ; - byte childDetailLevel; - posX = LevelPosUtil.getRegionModule(detailLevel, posX); - posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - for (int x = 0; x <= 1; x++) - { - for (int z = 0; z <= 1; z++) - { - childPosX = 2 * posX + x; - childPosZ = 2 * posZ + z; - childDetailLevel = (byte) (detailLevel - 1); - if (doesDataExist(childDetailLevel, childPosX, childPosZ)) - { - if (!(DataPointUtil.getHeight(data[childDetailLevel][childPosX][childPosZ]) == LodBuilder.DEFAULT_HEIGHT - && DataPointUtil.getDepth(data[childDetailLevel][childPosX][childPosZ]) == LodBuilder.DEFAULT_DEPTH)) - { - numberOfChildren++; - - tempRed += DataPointUtil.getRed(data[childDetailLevel][childPosX][childPosZ]); - tempGreen += DataPointUtil.getGreen(data[childDetailLevel][childPosX][childPosZ]); - tempBlue += DataPointUtil.getBlue(data[childDetailLevel][childPosX][childPosZ]); - tempHeight += DataPointUtil.getHeight(data[childDetailLevel][childPosX][childPosZ]); - tempDepth += DataPointUtil.getDepth(data[childDetailLevel][childPosX][childPosZ]); - } else - { - // void children have the default height (most likely -1) - // and represent a LOD with no blocks in it - numberOfVoidChildren++; - } - } - } - } - if (numberOfChildren > 0) - { - tempRed = tempRed / numberOfChildren; - tempGreen = tempGreen / numberOfChildren; - tempBlue = tempBlue / numberOfChildren; - tempHeight = tempHeight / numberOfChildren; - tempDepth = tempDepth / numberOfChildren; - } else if (numberOfVoidChildren > 0) - { - tempRed = (byte) 0; - tempGreen = (byte) 0; - tempBlue = (byte) 0; - tempHeight = LodBuilder.DEFAULT_HEIGHT; - tempDepth = LodBuilder.DEFAULT_DEPTH; - } - data[detailLevel][posX][posZ] = DataPointUtil.createDataPoint(tempHeight, tempDepth, tempRed, tempGreen, tempBlue); + dataContainer[detailLevel].updateData(dataContainer[detailLevel - 1], posX, posZ); } @@ -356,15 +287,22 @@ public class LodRegion if(detailLevel < minDetailLevel) return false; posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - return DataPointUtil.doesItExist(data[detailLevel][posX][posZ]); + return dataContainer[detailLevel].doesItExist(posX, posZ); } /** * @return */ - public DistanceGenerationMode getGenerationMode() + public byte getGenerationMode(byte detailLevel, int posX, int posZ) { - return generationMode; + if(dataContainer[detailLevel].doesItExist(posX,posZ)) + { + //We take the bottom information always + return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getData(posX,posZ)[0]); + }else + { + return DistanceGenerationMode.NONE.complexity; + } } public byte getMinDetailLevel() @@ -378,26 +316,26 @@ public class LodRegion * @param detailLevel * @return */ - public VerticalLevelContainer getLevel(byte detailLevel) + public LevelContainer getLevel(byte detailLevel) { if (detailLevel < minDetailLevel) { throw new IllegalArgumentException("getLevel asked for a level that does not exist: minimum " + minDetailLevel + " level requested " + detailLevel); } - return new VerticalLevelContainer(detailLevel, data[detailLevel]); + return dataContainer[detailLevel]; } /** - * @param verticalLevelContainer + * @param levelContainer */ - public void addLevel(VerticalLevelContainer verticalLevelContainer) + public void addLevel(LevelContainer levelContainer) { - if (verticalLevelContainer.detailLevel < minDetailLevel - 1) + if (levelContainer.getDetailLevel() < minDetailLevel - 1) { throw new IllegalArgumentException("addLevel requires a level that is at least the minimum level of the region -1 "); } - if (verticalLevelContainer.detailLevel == minDetailLevel - 1) minDetailLevel = verticalLevelContainer.detailLevel; - data[verticalLevelContainer.detailLevel] = verticalLevelContainer.data; + if (levelContainer.getDetailLevel() == minDetailLevel - 1) minDetailLevel = levelContainer.getDetailLevel(); + dataContainer[levelContainer.getDetailLevel()] = levelContainer; } @@ -410,7 +348,7 @@ public class LodRegion { for (byte tempLod = 0; tempLod < detailLevel; tempLod++) { - data[tempLod] = new long[0][0]; + dataContainer[tempLod] = null; } minDetailLevel = detailLevel; } @@ -423,10 +361,15 @@ public class LodRegion { if (detailLevel < minDetailLevel) { - for (byte tempLod = detailLevel; tempLod < minDetailLevel; tempLod++) + for (byte tempLod = (byte) (minDetailLevel - 1); tempLod >= minDetailLevel ; tempLod--) { int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - tempLod); - data[tempLod] = new long[size][size]; + if(dataContainer[tempLod + 1] == null) + { + /* TODO this can become either Single or Vertical*/ + dataContainer[tempLod + 1] = new SingleLevelContainer((byte) (tempLod + 1)); + } + dataContainer[tempLod] = dataContainer[tempLod+1].expand(); } minDetailLevel = detailLevel; } diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java index 589ade2b2..4528c5dc9 100644 --- a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -1,6 +1,7 @@ package com.seibel.lod.objects; import com.seibel.lod.builders.LodBuilder; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.util.DataPointUtil; import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodUtil; @@ -11,25 +12,53 @@ public class SingleLevelContainer implements LevelContainer public final long[][] data; + public SingleLevelContainer(byte detailLevel) + { + this.detailLevel = detailLevel; + int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + data = new long[size][size]; + } + public SingleLevelContainer(byte detailLevel, long[][] data) { this.detailLevel = detailLevel; this.data = data; } - public boolean putData(long[] data, int posX, int posZ){ + public boolean addData(long[] newData, int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - data[posX][posZ] = data[0]; + data[posX][posZ] = newData[0]; return true; } + private boolean addSingleData(long newData, int posX, int posZ){ + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + data[posX][posZ] = newData; + return true; + } public long[] getData(int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + //Improve this using a thread map to long[] + return new long[]{data[posX][posZ]}; + } + private long getSingleData(int posX, int posZ){ + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + //Improve this using a thread map to long[] return data[posX][posZ]; } + public byte getDetailLevel(){ + return detailLevel; + } + + public LevelContainer expand(){ + return new SingleLevelContainer((byte) (getDetailLevel() - 1)); + } + public SingleLevelContainer(String inputString) { @@ -41,71 +70,95 @@ public class SingleLevelContainer implements LevelContainer this.detailLevel = (byte) Integer.parseInt(inputString.substring(0, index)); int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel); - this.data = new long[size][size][1]; + this.data = new long[size][size]; for (int x = 0; x < size; x++) { for (int z = 0; z < size; z++) { lastIndex = index; index = inputString.indexOf(DATA_DELIMITER, lastIndex + 1); - data[x][z][0] = Long.parseLong(inputString.substring(lastIndex + 1, index), 16); + data[x][z] = Long.parseLong(inputString.substring(lastIndex + 1, index), 16); } } } - public long[] mergeData(long[][] dataArray, long[] newDataPoint, int[] indexes, long[] dataToCombine) + public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) { int numberOfChildren = 0; int numberOfVoidChildren = 0; + int tempAlpha = 0; int tempRed = 0; int tempGreen = 0; int tempBlue = 0; int tempHeight = 0; int tempDepth = 0; + int tempLight = 0; + byte tempGenMode = DistanceGenerationMode.SERVER.complexity; int childPosX; int childPosZ; - byte childDetailLevel; - for (int index = 0; x <= 4; x++) + long childData; + long data = 0; + byte childDetailLevel = (byte) (detailLevel - 1); + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + for (int x = 0; x <= 1; x++) { - childDetailLevel = (byte) (detailLevel - 1); - if (doesDataExist(childDetailLevel, childPosX, childPosZ)) + for (int z = 0; z <= 1; z++) + { + childPosX = 2 * posX + x; + childPosZ = 2 * posZ + z; + childData = lowerLevelContainer.getData(childPosX, childPosZ)[0]; + + if (DataPointUtil.doesItExist(childData)) { - if (!(DataPointUtil.getHeight(data[childDetailLevel][childPosX][childPosZ]) == LodBuilder.DEFAULT_HEIGHT - && DataPointUtil.getDepth(data[childDetailLevel][childPosX][childPosZ]) == LodBuilder.DEFAULT_DEPTH)) + if (!(DataPointUtil.isItVoid(childData))) { numberOfChildren++; - tempRed += DataPointUtil.getRed(data[childDetailLevel][childPosX][childPosZ]); - tempGreen += DataPointUtil.getGreen(data[childDetailLevel][childPosX][childPosZ]); - tempBlue += DataPointUtil.getBlue(data[childDetailLevel][childPosX][childPosZ]); - tempHeight += DataPointUtil.getHeight(data[childDetailLevel][childPosX][childPosZ]); - tempDepth += DataPointUtil.getDepth(data[childDetailLevel][childPosX][childPosZ]); + tempAlpha += DataPointUtil.getAlpha(childData); + tempRed += DataPointUtil.getRed(childData); + tempGreen += DataPointUtil.getGreen(childData); + tempBlue += DataPointUtil.getBlue(childData); + tempHeight += DataPointUtil.getHeight(childData); + tempDepth += DataPointUtil.getDepth(childData); } else { // void children have the default height (most likely -1) // and represent a LOD with no blocks in it numberOfVoidChildren++; } + tempGenMode = (byte) Math.min(tempGenMode, DataPointUtil.getGenerationMode(childData)); + }else + { + tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity); } } } if (numberOfChildren > 0) { + tempAlpha = tempAlpha / numberOfChildren; tempRed = tempRed / numberOfChildren; tempGreen = tempGreen / numberOfChildren; tempBlue = tempBlue / numberOfChildren; tempHeight = tempHeight / numberOfChildren; tempDepth = tempDepth / numberOfChildren; + tempLight = tempLight / numberOfChildren; + data = DataPointUtil.createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, tempHeight, tempDepth, tempLight, tempGenMode); + addSingleData(data, posX, posZ); } else if (numberOfVoidChildren > 0) { - tempRed = (byte) 0; - tempGreen = (byte) 0; - tempBlue = (byte) 0; - tempHeight = LodBuilder.DEFAULT_HEIGHT; - tempDepth = LodBuilder.DEFAULT_DEPTH; + data = DataPointUtil.createDataPoint(tempGenMode); + addSingleData(data, posX, posZ); } - data[detailLevel][posX][posZ] = DataPointUtil.createDataPoint(tempHeight, tempDepth, tempRed, tempGreen, tempBlue); + } + + + public boolean doesItExist(int posX, int posZ){ + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + //Improve this using a thread map to long[] + return DataPointUtil.doesItExist(getSingleData(posX, posZ)); } public String toDataString() @@ -125,7 +178,7 @@ public class SingleLevelContainer implements LevelContainer for (int z = 0; z < size; z++) { //Converting the dataToHex - stringBuilder.append(Long.toHexString(data[x][z][0])); + stringBuilder.append(Long.toHexString(data[x][z])); stringBuilder.append(DATA_DELIMITER); } } diff --git a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java index a8da77306..bec1522ca 100644 --- a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java @@ -13,13 +13,20 @@ public class VerticalLevelContainer implements LevelContainer public final long[][][] data; + public VerticalLevelContainer(byte detailLevel) + { + this.detailLevel = detailLevel; + int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + data = new long[size][size][]; + } + public VerticalLevelContainer(byte detailLevel, long[][][] data) { this.detailLevel = detailLevel; this.data = data; } - public boolean putData(long[] data, int posX, int posZ){ + public boolean addData(long[] data, int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); data[posX][posZ] = data @@ -55,9 +62,13 @@ public class VerticalLevelContainer implements LevelContainer } } - public long[] mergeData(long[][] dataArray, long[] newDataPoint, int[] indexes, long[] dataToCombine) - { + public void updateData(LevelContainer lowerLevelContainer, byte detailLevel, int posX, int posZ) + { + long[][] dataArray; + long[] newDataPoint; + int[] indexes; + long[] dataToCombine; //int maxSize = Math.max(Math.max(Math.max(dataArray[0].length, dataArray[1].length), dataArray[2].length), dataArray[3].length); //DetailDistanceUtil.getMaxVerticalData(detailLevel); //we are re-using these arrays so we must reset them to 0