diff --git a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java index e309e4ad1..dabf794ed 100644 --- a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java +++ b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java @@ -47,5 +47,4 @@ public enum DistanceGenerationMode * are adding the mod to a pre-existing world. * Singlethreaded - Slow (15-50 ms, with spikes up to 200 ms) */ SERVER; - } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index 82378f58b..a9f2bb637 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -1,5 +1,8 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; +import org.lwjgl.system.CallbackI; + import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; @@ -37,7 +40,7 @@ public class LodQuadTree { //data useful to render //if children are present then lodNodeData should be a combination of the lodData of the child. This can be //turned off by deselecting the recursive update in all update method. - private LodQuadTreeNode lodQuadTreeNode; + private LodQuadTreeNode lodNode; /* .____.____. | NW | NE | | @@ -91,11 +94,11 @@ public class LodQuadTree { /** * Constructor for generic level via the LodNodeData * - * @param lodQuadTreeNode object containing all the information of this node + * @param lodNode object containing all the information of this node */ - public LodQuadTree(LodQuadTree parent, LodQuadTreeNode lodQuadTreeNode) { + public LodQuadTree(LodQuadTree parent, LodQuadTreeNode lodNode) { this.parent = parent; - this.lodQuadTreeNode = lodQuadTreeNode; + this.lodNode = lodNode; this.children = new LodQuadTree[2][2]; this.nodeEmpty = true; this.nodeFull = false; @@ -126,18 +129,18 @@ public class LodQuadTree { } /** - * @param newLodQuadTreeNode data to put in the node + * @param newLodNode data to put in the node * @param updateHigherLevel will update the color and height of higher level only if true * @return true only if the QuadTree has been changed */ - public boolean setNodeAtLowerLevel(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) { + public boolean setNodeAtLowerLevel(LodQuadTreeNode newLodNode, boolean updateHigherLevel) { //check if we try to introduce a level that is higher or equal than the current one - byte targetLevel = newLodQuadTreeNode.level; - byte currentLevel = lodQuadTreeNode.level; + byte targetLevel = newLodNode.level; + byte currentLevel = lodNode.level; if (targetLevel < currentLevel) { - int posX = newLodQuadTreeNode.posX; - int posZ = newLodQuadTreeNode.posZ; - short widthRatio = (short) (lodQuadTreeNode.width / (2 * newLodQuadTreeNode.width)); + int posX = newLodNode.posX; + int posZ = newLodNode.posZ; + short widthRatio = (short) (lodNode.width / (2 * newLodNode.width)); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); //These two if fix the negative coordinate problema @@ -153,14 +156,16 @@ public class LodQuadTree { setChild(NS, WE); } LodQuadTree child = getChild(NS, WE); - if (!newLodQuadTreeNode.real && child.isNodeReal()) { + if (lodNode.compareComplexity(newLodNode) < 0) { + //the node we want to introduce is less complex than the current node + //we don't want to override higher complexity with lower complexity return false; } else { if (targetLevel == currentLevel - 1) { - child.setLodNodeData(newLodQuadTreeNode, true); + child.setLodNodeData(newLodNode, true); return true; } else { - return child.setNodeAtLowerLevel(newLodQuadTreeNode, updateHigherLevel); + return child.setNodeAtLowerLevel(newLodNode, updateHigherLevel); } } } else { @@ -172,23 +177,22 @@ public class LodQuadTree { /** * @param posX * @param posZ - * @param level + * @param targetLevel * @return */ - public LodQuadTreeNode getNodeAtLevelPosition(int posX, int posZ, byte level) { - byte targetLevel = level; - byte currentLevel = lodQuadTreeNode.level; + public LodQuadTreeNode getNodeAtLevelPosition(int posX, int posZ, byte targetLevel) { + byte currentLevel = lodNode.level; if (targetLevel == currentLevel) { - return lodQuadTreeNode; + return lodNode; } else if (targetLevel < currentLevel) { - short widthRatio = (short) (lodQuadTreeNode.width / (2 * Math.pow(2, level))); + short widthRatio = (short) (lodNode.width / (2 * Math.pow(2, targetLevel))); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); if (getChild(NS, WE) == null) { return null; } LodQuadTree child = getChild(NS, WE); - return child.getNodeAtLevelPosition(posX, posZ, level); + return child.getNodeAtLevelPosition(posX, posZ, targetLevel); } else { return null; } @@ -203,26 +207,26 @@ public class LodQuadTree { /** * setChild will put a child with given data in the given position * - * @param newLodQuadTreeNode data to put in the child + * @param newLodNode data to put in the child * @param NS North-South position * @param WE West-East position */ - public void setChild(LodQuadTreeNode newLodQuadTreeNode, int NS, int WE) { - if (newLodQuadTreeNode.level == lodQuadTreeNode.level - 1) { - children[NS][WE] = new LodQuadTree(this, lodQuadTreeNode); + public void setChild(LodQuadTreeNode newLodNode, int NS, int WE) { + if (newLodNode.level == lodNode.level - 1) { + children[NS][WE] = new LodQuadTree(this, lodNode); } } /** * setChild will put a child with given data in the given position * - * @param newLodQuadTreeNode data to put in the child + * @param newLodNode data to put in the child */ - public void setChild(LodQuadTreeNode newLodQuadTreeNode) { - if (newLodQuadTreeNode.level == lodQuadTreeNode.level - 1) { - int WE = newLodQuadTreeNode.posX % lodQuadTreeNode.posX; - int NS = newLodQuadTreeNode.posZ % lodQuadTreeNode.posZ; - children[NS][WE] = new LodQuadTree(this, lodQuadTreeNode); + public void setChild(LodQuadTreeNode newLodNode) { + if (newLodNode.level == lodNode.level - 1) { + int WE = newLodNode.posX % lodNode.posX; + int NS = newLodNode.posZ % lodNode.posZ; + children[NS][WE] = new LodQuadTree(this, lodNode); } } @@ -233,9 +237,9 @@ public class LodQuadTree { * @param WE West-East position */ public void setChild(int NS, int WE) { - int childX = lodQuadTreeNode.posX * 2 + WE; - int childZ = lodQuadTreeNode.posZ * 2 + NS; - children[NS][WE] = new LodQuadTree(this, (byte) (lodQuadTreeNode.level - 1), childX, childZ); + int childX = lodNode.posX * 2 + WE; + int childZ = lodNode.posZ * 2 + NS; + children[NS][WE] = new LodQuadTree(this, (byte) (lodNode.level - 1), childX, childZ); } /** @@ -259,9 +263,9 @@ public class LodQuadTree { } nodeFull = isFull; nodeEmpty = isEmpty; - lodQuadTreeNode.combineData(dataList); - if (lodQuadTreeNode.level < 9 && recursiveUpdate) { - this.parent.updateLevel(recursiveUpdate); + lodNode.combineData(dataList); + if (lodNode.level < 9 && recursiveUpdate) { + this.parent.updateLevel(true); } } @@ -274,14 +278,14 @@ public class LodQuadTree { * @param getOnlyLeaf if true it will return only leaf nodes * @return list of nodes */ - public List getNodeList(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf) { + public List getNodeList(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf) { List nodeList = new ArrayList<>(); if (isThereAnyChild()) { //There is at least 1 child if (!getOnlyLeaf - && !(getOnlyDirty && !lodQuadTreeNode.dirty) - && complexityMask.contains(lodQuadTreeNode.complexity)) { - nodeList.add(lodQuadTreeNode); + && !(getOnlyDirty && !lodNode.isDirty()) + && complexityMask.contains(lodNode.getComplexity())) { + nodeList.add(lodNode); } for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { @@ -293,9 +297,9 @@ public class LodQuadTree { } } else { //There are no children - if (!(getOnlyDirty && !lodQuadTreeNode.dirty) - || (complexityMask.contains((int) lodQuadTreeNode.complexity))){ - nodeList.add(lodQuadTreeNode); + if (!(getOnlyDirty && !lodNode.isDirty()) + && (complexityMask.contains(lodNode.getComplexity()))){ + nodeList.add(lodNode); } } @@ -312,37 +316,30 @@ public class LodQuadTree { * @param minDistance minimum distance from the player * @return */ - public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x - lodQuadTreeNode.centerX, 2) + Math.pow(z - lodQuadTreeNode.centerZ, 2)); + public List getNodeToRender(int x, int z, byte targetLevel, Set complexityMask, int maxDistance, int minDistance) { List distances = new ArrayList(); - distances.add(distance); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterX(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); + int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); - if (targetLevel > lodQuadTreeNode.level) { - return nodeList; - } - if ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/){ - return nodeList; - } - if (targetLevel == lodQuadTreeNode.level || !isNodeFull()) { - if (lodQuadTreeNode.voidNode) { - nodeList.add(lodQuadTreeNode); - return nodeList; + + if (!(targetLevel > lodNode.level || ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/))) { + if (targetLevel == lodNode.level || !isNodeFull()) { + if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity())) { + nodeList.add(lodNode); + } } else { - nodeList.add(lodQuadTreeNode); - return nodeList; - } - } else { - for (int NS = 0; NS <= 1; NS++) { - for (int WE = 0; WE <= 1; WE++) { - LodQuadTree child = getChild(NS,WE); - if (child != null) { - nodeList.addAll(child.getNodeToRender(x, z, targetLevel, maxDistance, minDistance)); + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + LodQuadTree child = getChild(NS, WE); + if (child != null) { + nodeList.addAll(child.getNodeToRender(x, z, targetLevel, complexityMask, maxDistance, minDistance)); + } } } } @@ -350,76 +347,65 @@ public class LodQuadTree { return nodeList; } + /** * Nodes that can be generated in the approximated version * A level is generated only if it has child and is higher than the target level and in the distance range * @param x * @param z * @param targetLevel + * @param complexityToGenerate * @param maxDistance * @param minDistance * @return */ - public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x - lodQuadTreeNode.centerX, 2) + Math.pow(z - lodQuadTreeNode.centerZ, 2)); + public List> getLevelToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) { + List distances = new ArrayList(); - distances.add(distance); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterX(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); + int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List> nodeList = new ArrayList<>(); - if ( targetLevel > lodQuadTreeNode.level ) { - return nodeList; - } - if ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/){ + if ( targetLevel > lodNode.level || ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/)) { return nodeList; } if(isNodeFull()) { //THIS LEVEL HAS CHILD SO IT'S GENERATED. - if (targetLevel != lodQuadTreeNode.level) { + if (targetLevel != lodNode.level) { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { if (getChild(NS,WE) == null) { setChild(NS,WE); } LodQuadTree child = getChild(NS,WE); - nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, maxDistance, minDistance)); - } - } - } - } else { - nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); - /* - if(isThereAnyChild()){ - for (int NS = 0; NS <= 1; NS++) { - for (int WE = 0; WE <= 1; WE++) { - if (children[NS][WE] == null) { - setChild(NS,WE); - LodQuadTree child = children[NS][WE]; - distance = (int) Math.sqrt(Math.pow(x - child.lodNodeData.centerX, 2) + Math.pow(z - child.lodNodeData.centerZ, 2)); - nodeList.add(new AbstractMap.SimpleEntry<>(child, distance)); - } + nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); } } }else{ - nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); + if(this.lodNode.getComplexity().compareTo(complexityToGenerate) > 0) { + //we want to regenerate a level only if we ask for higher complexity + nodeList.add(new AbstractMap.SimpleEntry<>(this, min) + } } - - */ + } else { + nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); } return nodeList; } + /** * simple getter for lodNodeData * * @return lodNodeData */ public LodQuadTreeNode getLodNodeData() { - return lodQuadTreeNode; + return lodNode; } /** @@ -429,10 +415,10 @@ public class LodQuadTree { * @param updateHigherLevel if true it will update all the upper levels. */ public void setLodNodeData(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) { - if (this.lodQuadTreeNode == null) { - this.lodQuadTreeNode = newLodQuadTreeNode; + if (this.lodNode == null) { + this.lodNode = newLodQuadTreeNode; } else { - this.lodQuadTreeNode.update(newLodQuadTreeNode); + this.lodNode.update(newLodQuadTreeNode); } //a recursive update is necessary to change higher level if (parent != null && updateHigherLevel) parent.updateLevel(true); @@ -446,21 +432,17 @@ public class LodQuadTree { return !nodeEmpty; } - public boolean isNodeReal() { - return lodQuadTreeNode.real; - } - public boolean isRenderable() { - return (lodQuadTreeNode != null); + return (lodNode != null); } public boolean isCoordinateInLevel(int x, int z){ - return !(lodQuadTreeNode.startX > x || lodQuadTreeNode.startZ > z || lodQuadTreeNode.endX < x || lodQuadTreeNode.endZ < z); + return !(lodNode.getStartX() > x || lodNode.getStartZ() > z || lodNode.getEndX() < x || lodNode.getEndZ() < z); } public String toString(){ - String s = lodQuadTreeNode.toString(); + String s = lodNode.toString(); return s; /* if(isThereAnyChild()){ diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index 563695ca3..bc317fad7 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -1,5 +1,6 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; @@ -251,11 +252,11 @@ public class LodQuadTreeDimension { * stored in the LOD. If an LOD already exists at the given * coordinates it will be overwritten. */ - public Boolean addNode(LodQuadTreeNode lodQuadTreeNode) + public Boolean addNode(LodQuadTreeNode lodNode) { RegionPos pos = new RegionPos( - lodQuadTreeNode.startX / 512, - lodQuadTreeNode.startZ / 512 + lodNode.getStartX() / 512, + lodNode.getStartZ() / 512 ); // don't continue if the region can't be saved @@ -272,10 +273,10 @@ public class LodQuadTreeDimension { region = new LodQuadTree(pos.x, pos.z); setRegion(region); } - boolean coorectlyAdded = region.setNodeAtLowerLevel(lodQuadTreeNode, true); + boolean coorectlyAdded = region.setNodeAtLowerLevel(lodNode, true); // don't save empty place holders to disk - if (lodQuadTreeNode.real && fileHandler != null) + if (fileHandler != null) { // mark the region as dirty so it will be saved to disk int xIndex = (pos.x - centerX) + halfWidth; @@ -310,16 +311,24 @@ public class LodQuadTreeDimension { */ } + /** + * return true if and only if the node at that position exist + */ + public boolean hasThisPositionBeenGenerated(int posX, int posZ, byte level) + { + return getLodFromCoordinates(posX,posZ,level).level == level + } + /** * method to get all the nodes that have to be rendered based on the position of the player * @return list of nodes */ - public List getNodeToRender(int x, int z, byte level, int maxDistance, int minDistance){ + public List getNodeToRender(int x, int z, byte level, Set complexityMask, int maxDistance, int minDistance){ int n = regions.length; List listOfData = new ArrayList<>(); for(int i=0; i getNodes(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf){ + public List getNodes(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf){ int n = regions.length; List listOfNodes = new ArrayList<>(); int xIndex; @@ -368,7 +377,7 @@ public class LodQuadTreeDimension { zIndex = (zRegion + centerZ) - halfWidth; region = getRegion(xIndex,zIndex); if (region != null){ - listOfNodes.addAll(region.getNodeList(getOnlyReal, getOnlyDirty, getOnlyLeaf)); + listOfNodes.addAll(region.getNodeList(complexityMask, getOnlyDirty, getOnlyLeaf)); } } } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index a5edd4ebe..288390f38 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -1,6 +1,8 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; +import net.minecraftforge.api.distmarker.Dist; import java.awt.*; import java.util.*; @@ -13,14 +15,13 @@ public class LodQuadTreeNode { /** this is how many pieces of data are exported when toData is called */ - public static final int NUMBER_OF_DELIMITERS = 9; + public static final int NUMBER_OF_DELIMITERS = 10; private static final Color INVISIBLE = new Color(0,0,0,0); - //Complexity indicate how complex is this node. For example a node that has been generated starting - //from a real chunk have the maximum complexity. A node that is generated starting from a fake approximated chunk - //has a low complexity - public byte complexity; + + //Complexity indicate how the block was built. This is important because we could use + public DistanceGenerationMode complexity; //level height goes from 0 to 9 with 0 the deepest (block size) and 9 the highest (region size) public final byte level; @@ -42,7 +43,7 @@ public class LodQuadTreeNode { //these 4 value indicate the corner of the LOD block //they can be named SW, SE, NW, NE as the cardinal direction. //the start values should always be smaller than the end values. - //All this value could be calculated from level and levelWidth + //All this value could be calculated from level, posx and posz //so they could be removed and replaced with just a getter public final int startX; public final int startZ; @@ -79,20 +80,49 @@ public class LodQuadTreeNode { endZ = startZ + width - 1; centerX = startX + width/2; centerZ = startZ + width/2; - lodDataPoint = new LodDataPoint() - real = false; + lodDataPoint = new LodDataPoint(); + complexity = null; dirty = true; voidNode = true; } + /** + * Constructor for a LodNodeData + * @param level + * @param posX + * @param posZ + * @param height + * @param depth + * @param color + * @param complexity + */ + public LodQuadTreeNode(byte level, int posX, int posZ, short height , short depth , Color color, DistanceGenerationMode complexity){ + this(level, posX, posZ, new LodDataPoint(height,depth,color), complexity); + } + + /** + * Constructor for a LodNodeData + * @param level + * @param posX + * @param posZ + * @param height + * @param depth + * @param color + * @param complexity + */ + public LodQuadTreeNode(byte level, int posX, int posZ, int height , int depth , Color color, DistanceGenerationMode complexity){ + this(level, posX, posZ, new LodDataPoint(height,depth,color), complexity); + } + /** * Constructor for a LodNodeData * @param level level of this * @param posX * @param posZ + * @param lodDataPoint * @param complexity */ - public LodQuadTreeNode(byte level, int posX, int posZ, LodDataPoint lodDataPoint, byte complexity){ + public LodQuadTreeNode(byte level, int posX, int posZ, LodDataPoint lodDataPoint, DistanceGenerationMode complexity){ this.level = level; this.posX = posX; this.posZ = posZ; @@ -104,7 +134,7 @@ public class LodQuadTreeNode { centerX = startX + width/2; centerZ = startZ + width/2; this.lodDataPoint = lodDataPoint; - this.real = real; + this.complexity = complexity; dirty = true; voidNode = false; } @@ -116,6 +146,9 @@ public class LodQuadTreeNode { index = data.indexOf(DATA_DELIMITER, 0); this.level = (byte) Integer.parseInt(data.substring(0,index)); + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + this.complexity = DistanceGenerationMode.valueOf(data.substring(lastIndex+1,index)); lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); @@ -127,11 +160,11 @@ public class LodQuadTreeNode { lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + short height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.depth = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + short depth = (short) Integer.parseInt(data.substring(lastIndex+1,index)); lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); @@ -145,14 +178,13 @@ public class LodQuadTreeNode { lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); int a = Integer.parseInt(data.substring(lastIndex+1,index)); - this.color = new Color(r,g,b,a); + Color color = new Color(r,g,b,a); + lodDataPoint = new LodDataPoint(height,depth,color); - int complexity = Integer.parseInt(data.substring(lastIndex+1,index)); - this.real = (val == 1); - width = (short) Math.pow(2, level); - - val = Integer.parseInt(data.substring(lastIndex+1,index)); + int val = Integer.parseInt(data.substring(lastIndex+1,index)); this.voidNode = (val == 1); + + width = (short) Math.pow(2, level); startX = posX * width; startZ = posZ * width; endX = startX + width - 1; @@ -163,7 +195,7 @@ public class LodQuadTreeNode { } public void update(LodQuadTreeNode lodQuadTreeNode){ - this.lodDataPoint = lodQuadTreeNode.lodDataPoint + this.lodDataPoint = lodQuadTreeNode.lodDataPoint; this.complexity = lodQuadTreeNode.complexity; this.voidNode = lodQuadTreeNode.voidNode; dirty = true; @@ -172,9 +204,6 @@ public class LodQuadTreeNode { public LodDataPoint getLodDataPoint(){ return lodDataPoint; } - public byte getComplexity(){ - return complexity; - } public void combineData(List dataList){ if(dataList.isEmpty()){ @@ -189,7 +218,16 @@ public class LodQuadTreeNode { int blue = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getBlue()).sum()/dataList.size(); Color color = new Color(red,green,blue); lodDataPoint = new LodDataPoint(height,depth,color); - complexity = (byte) dataList.stream().mapToInt(x -> x.complexity).max().getAsInt(); + + //the new complexity equal to the lowest complexity of the list + DistanceGenerationMode minComplexity = DistanceGenerationMode.SERVER; + dataList.forEach(x -> { + if (minComplexity.compareTo(x.complexity) < 0){ + minComplexity = x.complexity; + } + }); + complexity = minComplexity; + voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; } dirty = true; @@ -197,7 +235,11 @@ public class LodQuadTreeNode { public int hashCode(){ - return Objects.hash(this.complexity, this.level, this.posX, this.posZ, this.color, this.real, this.voidNode); + return Objects.hash(this.complexity, this.level, this.posX, this.posZ, this.lodDataPoint, this.voidNode); + } + + public int compareComplexity(LodQuadTreeNode other){ + return this.complexity.compareTo(other.complexity); } @@ -206,8 +248,8 @@ public class LodQuadTreeNode { && this.level == other.level && this.posX == other.posX && this.posZ == other.posZ - && this.color.equals(other.color) - && this.real == other.real + && this.lodDataPoint.equals(other.lodDataPoint) + && this.complexity == other.complexity && this.voidNode == other.voidNode); } @@ -216,18 +258,17 @@ public class LodQuadTreeNode { * Outputs all data in a csv format */ public String toData(){ - String s = Integer.toString(level) + DATA_DELIMITER + String s = ((int) level) + DATA_DELIMITER + + complexity.toString() + DATA_DELIMITER + posX + DATA_DELIMITER + posZ + DATA_DELIMITER - + Integer.toString(height) + DATA_DELIMITER - + Integer.toString(depth) + DATA_DELIMITER - + color.getRed() + DATA_DELIMITER - + color.getGreen() + DATA_DELIMITER - + color.getBlue() + DATA_DELIMITER - + color.getAlpha() + DATA_DELIMITER; - int val = real ? 1 : 0; - s += val + DATA_DELIMITER; - val = voidNode ? 1 : 0; + + ((int) lodDataPoint.height) + DATA_DELIMITER + + ((int) lodDataPoint.depth) + DATA_DELIMITER + + lodDataPoint.color.getRed() + DATA_DELIMITER + + lodDataPoint.color.getGreen() + DATA_DELIMITER + + lodDataPoint.color.getBlue() + DATA_DELIMITER + + lodDataPoint.color.getAlpha() + DATA_DELIMITER; + int val = voidNode ? 1 : 0; s += val + DATA_DELIMITER; return s; } @@ -238,4 +279,59 @@ public class LodQuadTreeNode { { return this.toData(); } + + + // This getters should be used + + public byte getLevel() { + return level; + } + + public DistanceGenerationMode getComplexity() { + return complexity; + } + + public short getWidth() { + return width; + } + + public int getPosX() { + return posX; + } + + public int getPosZ() { + return posZ; + } + + public int getStartX() { + return startX; + } + + public int getStartZ() { + return startZ; + } + + public int getEndX() { + return endX; + } + + public int getEndZ() { + return endZ; + } + + public int getCenterX() { + return centerX; + } + + public int getCenterZ() { + return centerZ; + } + + public boolean isVoidNode() { + return voidNode; + } + + public boolean isDirty() { + return dirty; + } } diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 73cd770be..7396dd319 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -1,5 +1,6 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.util.BiomeColorsUtils; import kaptainwutax.biomeutils.source.OverworldBiomeSource; import kaptainwutax.mcutils.version.MCVersion; @@ -18,9 +19,7 @@ import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import javax.imageio.ImageIO; import javax.swing.JFrame; @@ -159,7 +158,13 @@ public class QuadTreeImage extends JPanel { lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); System.out.println(lodList.size()); */ - List lodList = dim.getNodes(false,false,false); + Set complexityMask = new HashSet<>(); + complexityMask.add(DistanceGenerationMode.SERVER); + complexityMask.add(DistanceGenerationMode.FEATURES); + complexityMask.add(DistanceGenerationMode.SURFACE); + complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); + complexityMask.add(DistanceGenerationMode.BIOME_ONLY); + List lodList = dim.getNodes(complexityMask,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200));