revert LodQuadTree region to LodQuadTree and other refactors
This commit is contained in:
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.seibel.lod.objects.LodQuadTreeRegion;
|
||||
import com.seibel.lod.objects.LodQuadTree;
|
||||
import com.seibel.lod.objects.LodQuadTreeDimension;
|
||||
import com.seibel.lod.objects.LodQuadTreeNode;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
@@ -98,7 +98,7 @@ public class LodQuadTreeDimensionFileHandler {
|
||||
* Return the LodQuadTree region at the given coordinates.
|
||||
* (null if the file doesn't exist)
|
||||
*/
|
||||
public LodQuadTreeRegion loadRegionFromFile(int regionX, int regionZ)
|
||||
public LodQuadTree loadRegionFromFile(int regionX, int regionZ)
|
||||
{
|
||||
|
||||
String fileName = getFileNameAndPathForRegion(regionX, regionZ);
|
||||
@@ -195,7 +195,7 @@ public class LodQuadTreeDimensionFileHandler {
|
||||
// problem reading the file
|
||||
return null;
|
||||
}
|
||||
return new LodQuadTreeRegion(dataList,regionX, regionZ);
|
||||
return new LodQuadTree(dataList,regionX, regionZ);
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ public class LodQuadTreeDimensionFileHandler {
|
||||
* 2. This will save to the LodDimension that this
|
||||
* handler is associated with.
|
||||
*/
|
||||
private void saveRegionToDisk(LodQuadTreeRegion region)
|
||||
private void saveRegionToDisk(LodQuadTree region)
|
||||
{
|
||||
// convert chunk coordinates to region
|
||||
// coordinates
|
||||
|
||||
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* This file is part of the LOD Mod, licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.seibel.lod.objects;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.seibel.lod.enums.DistanceGenerationMode;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
|
||||
/**
|
||||
* This object contains all data useful to render LodBlock in a region (32x32 chunk to 512x512 block)
|
||||
* for every node it contains the border of said node, its size, its block position in the world,
|
||||
* color, height and depth.
|
||||
*
|
||||
* @author Leonardo Amato
|
||||
* @author James Seibel
|
||||
* @version 8-7-2021
|
||||
*/
|
||||
public class LodQuadTree
|
||||
{
|
||||
// note:
|
||||
// The term node correspond to a LodQuadTree object
|
||||
|
||||
/*
|
||||
Example on how a LodQuadTreeRegion would be rendered (the number corresponds to the level of the LodNodeData)
|
||||
.___.___._______._______________.
|
||||
|6|6| 7 | | |
|
||||
|6|6|___| 8 | |
|
||||
| 7 | 7 | | |
|
||||
|___|___|_______| 9 |
|
||||
| | | |
|
||||
| 8 | 8 | |
|
||||
| | | |
|
||||
|_______|_______|_______________|
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| 9 | 9 |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|_______________|_______________|
|
||||
*/
|
||||
|
||||
|
||||
/** If true SetNodesAtLowerLevel will update the color and height of all higher level nodes */
|
||||
public static boolean UPDATE_HIGHER_LEVEL = true;
|
||||
|
||||
//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 lodNode;
|
||||
|
||||
/*
|
||||
.____.____.
|
||||
| NW | NE | |
|
||||
|____|____| Z
|
||||
| SW | SE | |
|
||||
|____|____| V
|
||||
-----X---->
|
||||
|
||||
North - negative z
|
||||
South - positive z
|
||||
West - negative x
|
||||
east - positive x
|
||||
*/
|
||||
|
||||
|
||||
/** treeFull is true if and only if all child are not null */
|
||||
private boolean treeFull;
|
||||
private boolean treeEmpty;
|
||||
|
||||
/**
|
||||
* The four child are based on the four diagonal cardinal directions.
|
||||
* The first index is for North and South and the second index is for East and West. <br>
|
||||
* Children should always be null for level 0.
|
||||
*/
|
||||
private final LodQuadTree[][] children;
|
||||
|
||||
//parent should always be null for level 9, and always not null for other levels.
|
||||
private final LodQuadTree parent;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for level 0 without LodNodeData (region level constructor)
|
||||
*
|
||||
* @param regionX indicate the x region position of the node
|
||||
* @param regionZ indicate the z region position of the node
|
||||
*/
|
||||
//maybe the use of useLevelCoordinate could be changed. I could use a builder to do all this work.
|
||||
public LodQuadTree(RegionPos regionPos)
|
||||
{
|
||||
this(null, new LodQuadTreeNode(LodQuadTreeNode.REGION_LEVEL, regionPos.x, regionPos.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for generic world without LOD data
|
||||
*
|
||||
* @param parent parent of this node
|
||||
* @param level level of this note
|
||||
* @param posX position x in the level
|
||||
* @param posZ position z in the level
|
||||
*/
|
||||
public LodQuadTree(LodQuadTree parent, byte level, RegionPos regionPos)
|
||||
{
|
||||
this(parent, new LodQuadTreeNode(level, regionPos.x, regionPos.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a generic world via the LodNodeData
|
||||
*
|
||||
* @param newLodNode LodQuadTreeNode containing all the information of this node
|
||||
*/
|
||||
public LodQuadTree(LodQuadTree newParent, LodQuadTreeNode newLodNode)
|
||||
{
|
||||
parent = newParent;
|
||||
lodNode = newLodNode;
|
||||
children = new LodQuadTree[2][2];
|
||||
treeEmpty = true;
|
||||
treeFull = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using a dataList
|
||||
*
|
||||
* @param dataList list of LodNodeData to put in this LodQuadTree
|
||||
* @param regionX x region coordinate
|
||||
* @param regionZ z region coordinate
|
||||
*/
|
||||
public LodQuadTree(List<LodQuadTreeNode> dataList, int regionX, int regionZ)
|
||||
{
|
||||
this(null, new LodQuadTreeNode(LodQuadTreeNode.REGION_LEVEL, regionX, regionZ));
|
||||
setNodesAtLowerLevel(dataList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param dataList list of data to put in the node
|
||||
*/
|
||||
public void setNodesAtLowerLevel(List<LodQuadTreeNode> dataList)
|
||||
{
|
||||
for (LodQuadTreeNode lodQuadTreeNode : dataList)
|
||||
{
|
||||
this.setNodeAtLowerLevel(lodQuadTreeNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newLowerLodNode data to put in the node
|
||||
* @return true only if the QuadTree has been changed
|
||||
*/
|
||||
public boolean setNodeAtLowerLevel(LodQuadTreeNode newLowerLodNode)
|
||||
{
|
||||
byte targetLevel = newLowerLodNode.detailLevel;
|
||||
byte currentLevel = lodNode.detailLevel;
|
||||
|
||||
if (targetLevel >= currentLevel)
|
||||
{
|
||||
// we can't add a node that has a equal or higher
|
||||
// detail level than this region
|
||||
return false;
|
||||
}
|
||||
|
||||
short widthRatio = (short) (lodNode.width / (2 * newLowerLodNode.width));
|
||||
int WE = Math.abs(Math.floorDiv(newLowerLodNode.posX , widthRatio) % 2);
|
||||
int NS = Math.abs(Math.floorDiv(newLowerLodNode.posZ , widthRatio) % 2);
|
||||
|
||||
if (getChild(NS, WE) == null)
|
||||
{
|
||||
// if this child doesn't exist, create an empty one
|
||||
setChild(NS, WE);
|
||||
}
|
||||
|
||||
LodQuadTree child = getChild(NS, WE);
|
||||
if (lodNode.compareComplexity(newLowerLodNode) > 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)
|
||||
{
|
||||
// we are at the level we want to add the newLowerLodNode
|
||||
child.setLodNodeData(newLowerLodNode);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// recurse until we reach the level we want to add the newLowerLodNode
|
||||
return child.setNodeAtLowerLevel(newLowerLodNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the LodQuadTreeNode at the given chunkPos and detailLevel.
|
||||
* Returns null if no such LodQuadTreeNode exists.
|
||||
*/
|
||||
public LodQuadTreeNode getNodeAtChunkPos(ChunkPos chunkPos, int detailLevel)
|
||||
{
|
||||
if (detailLevel > LodQuadTreeNode.REGION_LEVEL)
|
||||
throw new IllegalArgumentException("getNodeAtChunkPos given a level of \"" + detailLevel + "\" when \"" + LodQuadTreeNode.REGION_LEVEL + "\" is the max.");
|
||||
|
||||
|
||||
byte currentDetailLevel = lodNode.detailLevel;
|
||||
if (detailLevel == currentDetailLevel)
|
||||
{
|
||||
return lodNode;
|
||||
}
|
||||
else if (detailLevel < currentDetailLevel)
|
||||
{
|
||||
// the detail level we need is lower, go down a layer
|
||||
short widthRatio = (short) (lodNode.width / (2 * Math.pow(2, detailLevel)));
|
||||
int WE = Math.abs(Math.floorDiv(chunkPos.x , widthRatio) % 2);
|
||||
int NS = Math.abs(Math.floorDiv(chunkPos.z , widthRatio) % 2);
|
||||
if (getChild(NS, WE) == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
LodQuadTree child = getChild(NS, WE);
|
||||
return child.getNodeAtChunkPos(chunkPos, detailLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the detail level was higher than this region's
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public LodQuadTree getChild(int NS, int WE)
|
||||
{
|
||||
return children[NS][WE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a child with the given data into the given position.
|
||||
*
|
||||
* @param newLodNode data to put in the child
|
||||
*/
|
||||
public void setChild(LodQuadTreeNode newLodNode)
|
||||
{
|
||||
// the child must be 1 detail level lower than this region
|
||||
if (newLodNode.detailLevel == lodNode.detailLevel - 1)
|
||||
{
|
||||
int WE = newLodNode.posX % lodNode.posX;
|
||||
int NS = newLodNode.posZ % lodNode.posZ;
|
||||
children[NS][WE] = new LodQuadTree(this, lodNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an empty child in the given position.
|
||||
*
|
||||
* @param NS North-South position
|
||||
* @param WE West-East position
|
||||
*/
|
||||
public void setChild(int NS, int WE)
|
||||
{
|
||||
// TODO is this correctly converting to a regionPos?
|
||||
int childRegionX = lodNode.posX * 2 + WE;
|
||||
int childRegionZ = lodNode.posZ * 2 + NS;
|
||||
|
||||
children[NS][WE] = new LodQuadTree(this, (byte) (lodNode.detailLevel - 1), new RegionPos(childRegionX, childRegionZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this region's data, specifically levelFull and lodNodeData.
|
||||
*
|
||||
* @param recursiveUpdate if recursive is true the update will rise up to the level 0
|
||||
*/
|
||||
private void updateRegion(boolean recursiveUpdate)
|
||||
{
|
||||
boolean isFull = true;
|
||||
boolean isEmpty = true;
|
||||
|
||||
// determine if this region is empty or full
|
||||
List<LodQuadTreeNode> dataList = new ArrayList<>();
|
||||
for (int NS = 0; NS <= 1; NS++)
|
||||
{
|
||||
for (int WE = 0; WE <= 1; WE++)
|
||||
{
|
||||
if (getChild(NS,WE) != null)
|
||||
{
|
||||
dataList.add(getChild(NS,WE).getLodNodeData());
|
||||
isEmpty = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isFull = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
treeFull = isFull;
|
||||
treeEmpty = isEmpty;
|
||||
|
||||
// update this regions
|
||||
lodNode.combineData(dataList);
|
||||
|
||||
// update sub regions if requested
|
||||
if (lodNode.detailLevel < LodQuadTreeNode.REGION_LEVEL && recursiveUpdate)
|
||||
{
|
||||
this.parent.updateRegion(recursiveUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns nodes that match the given mask.
|
||||
*
|
||||
* @param complexityMask holds the DistanceGenerationModes to accept
|
||||
* @param getOnlyDirty if true it will return only dirty nodes
|
||||
* @param getOnlyLeaf if true it will return only leaf nodes
|
||||
* @return list of nodes
|
||||
*/
|
||||
public List<LodQuadTreeNode> getNodeListWithMask(Set<DistanceGenerationMode> complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf)
|
||||
{
|
||||
List<LodQuadTreeNode> nodeList = new ArrayList<>();
|
||||
|
||||
if (hasChildren())
|
||||
{
|
||||
//There is at least 1 child
|
||||
|
||||
// this detail level's node
|
||||
if (!getOnlyLeaf && !(getOnlyDirty && !lodNode.isDirty())
|
||||
&& complexityMask.contains(lodNode.getComplexity()))
|
||||
{
|
||||
nodeList.add(lodNode);
|
||||
}
|
||||
|
||||
// search the children for valid nodes
|
||||
for (int NS = 0; NS <= 1; NS++)
|
||||
{
|
||||
for (int WE = 0; WE <= 1; WE++)
|
||||
{
|
||||
LodQuadTree child = children[NS][WE];
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
nodeList.addAll(child.getNodeListWithMask(complexityMask, getOnlyDirty, getOnlyLeaf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This tree has no children
|
||||
|
||||
if (!(getOnlyDirty && !lodNode.isDirty()) && (complexityMask.contains(lodNode.getComplexity())))
|
||||
{
|
||||
nodeList.add(lodNode);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return all the nodes that can be rendered
|
||||
*
|
||||
* @param playerPos position of the player
|
||||
* @param targetLevel minimum level that can be rendered
|
||||
* @param maxDistance maximum distance from the player
|
||||
* @param minDistance minimum distance from the player
|
||||
* @return
|
||||
*/
|
||||
public List<LodQuadTreeNode> getNodeToRender(BlockPos playerPos, int targetLevel, Set<DistanceGenerationMode> complexityMask, int maxDistance, int minDistance)
|
||||
{
|
||||
int x = playerPos.getX();
|
||||
int z = playerPos.getZ();
|
||||
|
||||
List<Integer> distances = new ArrayList<>();
|
||||
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<LodQuadTreeNode> nodeList = new ArrayList<>();
|
||||
|
||||
|
||||
if (targetLevel <= lodNode.detailLevel && ((min <= maxDistance && max >= minDistance)))
|
||||
{
|
||||
if (targetLevel == lodNode.detailLevel || !isNodeFull())
|
||||
{
|
||||
// we have either reached the right detail level or this tree isn't full
|
||||
|
||||
if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity()))
|
||||
{
|
||||
// this node isn't void and has the complexity level we are looking for
|
||||
nodeList.add(lodNode);
|
||||
}
|
||||
}
|
||||
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(playerPos, targetLevel, complexityMask, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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<AbstractMap.SimpleEntry<LodQuadTreeNode, Integer>> getNodesToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) {
|
||||
|
||||
List<Integer> distances = new ArrayList<>();
|
||||
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<AbstractMap.SimpleEntry<LodQuadTreeNode, Integer>> nodeList = new ArrayList<>();
|
||||
if (targetLevel <= lodNode.detailLevel && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) {
|
||||
if(!hasChildren() || targetLevel == lodNode.detailLevel){
|
||||
if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0 ) {
|
||||
nodeList.add(new AbstractMap.SimpleEntry<LodQuadTreeNode, Integer>(this.lodNode, min));
|
||||
}
|
||||
}else {
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
if (getChild(NS, WE) == null) {
|
||||
setChild(NS, WE);
|
||||
}
|
||||
nodeList.addAll(getChild(NS, WE).getNodesToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* simple getter for lodNodeData
|
||||
*
|
||||
* @return lodNodeData
|
||||
*/
|
||||
public LodQuadTreeNode getLodNodeData() {
|
||||
return lodNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for lodNodeData, to maintain a correct relationship between level this method force update on all parent
|
||||
*
|
||||
* @param newLodQuadTreeNode data to set
|
||||
* @param updateHigherLevel if true it will update all the upper levels.
|
||||
*/
|
||||
public void setLodNodeData(LodQuadTreeNode newLodQuadTreeNode)
|
||||
{
|
||||
if (this.lodNode == null) {
|
||||
this.lodNode = newLodQuadTreeNode;
|
||||
} else {
|
||||
this.lodNode.update(newLodQuadTreeNode);
|
||||
}
|
||||
//a recursive update is necessary to change higher level
|
||||
if (parent != null && UPDATE_HIGHER_LEVEL) parent.updateRegion(true);
|
||||
}
|
||||
|
||||
public boolean isNodeFull() {
|
||||
return treeFull;
|
||||
}
|
||||
|
||||
public boolean hasChildren()
|
||||
{
|
||||
return !treeEmpty;
|
||||
}
|
||||
|
||||
public boolean isRenderable() {
|
||||
return (lodNode != null);
|
||||
}
|
||||
|
||||
|
||||
public boolean isCoordinateInLevel(int x, int z){
|
||||
return (lodNode.getStartX() * lodNode.width <= x && lodNode.getStartZ() * lodNode.width <= z && lodNode.getEndX() * lodNode.width >= x && lodNode.getEndZ() * lodNode.width >= z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
String s = lodNode.toString();
|
||||
return s;
|
||||
/*
|
||||
if(isThereAnyChild()){
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTree child = children[NS][WE];
|
||||
if (child != null) {
|
||||
s += '\n' + child.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public class LodQuadTreeDimension
|
||||
}
|
||||
|
||||
|
||||
public volatile LodQuadTreeRegion regions[][];
|
||||
public volatile LodQuadTree regions[][];
|
||||
public volatile boolean isRegionDirty[][];
|
||||
|
||||
/** a chunk Position */
|
||||
@@ -131,7 +131,7 @@ public class LodQuadTreeDimension
|
||||
|
||||
|
||||
|
||||
regions = new LodQuadTreeRegion[width][width];
|
||||
regions = new LodQuadTree[width][width];
|
||||
isRegionDirty = new boolean[width][width];
|
||||
|
||||
// populate isRegionDirty
|
||||
@@ -253,7 +253,7 @@ public class LodQuadTreeDimension
|
||||
* Returns null if the region doesn't exist
|
||||
* or is outside the loaded area.
|
||||
*/
|
||||
public LodQuadTreeRegion getRegion(RegionPos regionPos)
|
||||
public LodQuadTree getRegion(RegionPos regionPos)
|
||||
{
|
||||
int xIndex = (regionPos.x - center.x) + halfWidth;
|
||||
int zIndex = (regionPos.z - center.z) + halfWidth;
|
||||
@@ -267,7 +267,7 @@ public class LodQuadTreeDimension
|
||||
regions[xIndex][zIndex] = getRegionFromFile(regionPos.x, regionPos.z);
|
||||
if (regions[xIndex][zIndex] == null)
|
||||
{
|
||||
regions[xIndex][zIndex] = new LodQuadTreeRegion(regionPos.x, regionPos.z);
|
||||
regions[xIndex][zIndex] = new LodQuadTree(regionPos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ public class LodQuadTreeDimension
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException if newRegion is outside what can be stored in this LodDimension.
|
||||
*/
|
||||
public void addOrOverwriteRegion(LodQuadTreeRegion newRegion) throws ArrayIndexOutOfBoundsException
|
||||
public void addOrOverwriteRegion(LodQuadTree newRegion) throws ArrayIndexOutOfBoundsException
|
||||
{
|
||||
int xIndex = (newRegion.getLodNodeData().posX - center.x) + halfWidth;
|
||||
int zIndex = (center.z - newRegion.getLodNodeData().posZ) + halfWidth;
|
||||
@@ -299,7 +299,8 @@ public class LodQuadTreeDimension
|
||||
{
|
||||
int regionX;
|
||||
int regionZ;
|
||||
LodQuadTreeRegion region;
|
||||
RegionPos regionPos;
|
||||
LodQuadTree region;
|
||||
|
||||
for(int x = 0; x < regions.length; x++)
|
||||
{
|
||||
@@ -307,12 +308,13 @@ public class LodQuadTreeDimension
|
||||
{
|
||||
regionX = (x + center.x) - halfWidth;
|
||||
regionZ = (z + center.z) - halfWidth;
|
||||
region = getRegion(new RegionPos(regionX,regionZ));
|
||||
regionPos = new RegionPos(regionX,regionZ);
|
||||
region = getRegion(regionPos);
|
||||
|
||||
if (region == null)
|
||||
{
|
||||
// if no region exists, create it
|
||||
region = new LodQuadTreeRegion(regionX, regionZ);
|
||||
region = new LodQuadTree(regionPos);
|
||||
addOrOverwriteRegion(region);
|
||||
}
|
||||
}
|
||||
@@ -335,15 +337,15 @@ public class LodQuadTreeDimension
|
||||
return false;
|
||||
}
|
||||
|
||||
LodQuadTreeRegion region = getRegion(new RegionPos(regionPos.x, regionPos.z));
|
||||
LodQuadTree region = getRegion(regionPos);
|
||||
|
||||
if (region == null)
|
||||
{
|
||||
// if no region exists, create it
|
||||
region = new LodQuadTreeRegion(regionPos.x, regionPos.z);
|
||||
region = new LodQuadTree(regionPos);
|
||||
addOrOverwriteRegion(region);
|
||||
}
|
||||
boolean nodeAdded = region.setNodeAtLowerLevel(lodNode, true);
|
||||
boolean nodeAdded = region.setNodeAtLowerLevel(lodNode);
|
||||
|
||||
// only save valid LODs to disk
|
||||
if (!lodNode.dontSave && fileHandler != null)
|
||||
@@ -385,14 +387,14 @@ public class LodQuadTreeDimension
|
||||
// TODO possibly put this in LodUtil
|
||||
int regionPosX = Math.floorDiv(chunkPos.x, (int) Math.pow(2,LodQuadTreeNode.REGION_LEVEL - detailLevel));
|
||||
int regionPosZ = Math.floorDiv(chunkPos.z, (int) Math.pow(2,LodQuadTreeNode.REGION_LEVEL - detailLevel));
|
||||
LodQuadTreeRegion region = getRegion(new RegionPos(regionPosX, regionPosZ));
|
||||
LodQuadTree region = getRegion(new RegionPos(regionPosX, regionPosZ));
|
||||
|
||||
if(region == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return region.getNodeAtChunkPos(chunkPos.x, chunkPos.z, detailLevel);
|
||||
return region.getNodeAtChunkPos(chunkPos, detailLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,7 +422,7 @@ public class LodQuadTreeDimension
|
||||
{
|
||||
for(int j = 0; j < regions.length; j++)
|
||||
{
|
||||
listOfData.addAll(regions[i][j].getNodeToRender(playerPos.getX(), playerPos.getZ(), detailLevel, complexityMask, maxDistance, minDistance));
|
||||
listOfData.addAll(regions[i][j].getNodeToRender(playerPos, detailLevel, complexityMask, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +437,8 @@ public class LodQuadTreeDimension
|
||||
{
|
||||
int regionX;
|
||||
int regionZ;
|
||||
LodQuadTreeRegion region;
|
||||
LodQuadTree region;
|
||||
RegionPos regionPos;
|
||||
List<Map.Entry<LodQuadTreeNode,Integer>> listOfQuadTree = new ArrayList<>();
|
||||
|
||||
// go through every region we have stored
|
||||
@@ -445,11 +448,12 @@ public class LodQuadTreeDimension
|
||||
{
|
||||
regionX = (xIndex + center.x) - halfWidth;
|
||||
regionZ = (zIndex + center.z) - halfWidth;
|
||||
region = getRegion(new RegionPos(regionX,regionZ));
|
||||
regionPos = new RegionPos(regionX,regionZ);
|
||||
region = getRegion(regionPos);
|
||||
|
||||
if (region == null)
|
||||
{
|
||||
region = new LodQuadTreeRegion(regionX, regionZ);
|
||||
region = new LodQuadTree(regionPos);
|
||||
addOrOverwriteRegion(region);
|
||||
}
|
||||
|
||||
@@ -462,7 +466,7 @@ public class LodQuadTreeDimension
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LodQuadTreeRegion#getNodeListWithMask
|
||||
* @see LodQuadTree#getNodeListWithMask
|
||||
*/
|
||||
public List<LodQuadTreeNode> getNodesWithMask(Set<DistanceGenerationMode> complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf)
|
||||
{
|
||||
@@ -470,7 +474,7 @@ public class LodQuadTreeDimension
|
||||
|
||||
int xIndex;
|
||||
int zIndex;
|
||||
LodQuadTreeRegion region;
|
||||
LodQuadTree region;
|
||||
|
||||
// go through every region we have stored
|
||||
for(int xRegion = 0; xRegion < regions.length; xRegion++)
|
||||
@@ -494,7 +498,7 @@ public class LodQuadTreeDimension
|
||||
* Get the region at the given X and Z coordinates from the
|
||||
* RegionFileHandler.
|
||||
*/
|
||||
public LodQuadTreeRegion getRegionFromFile(int regionX, int regionZ)
|
||||
public LodQuadTree getRegionFromFile(int regionX, int regionZ)
|
||||
{
|
||||
if (fileHandler != null)
|
||||
return fileHandler.loadRegionFromFile(regionX, regionZ);
|
||||
@@ -541,12 +545,12 @@ public class LodQuadTreeDimension
|
||||
public int getNumberOfLods()
|
||||
{
|
||||
int numbLods = 0;
|
||||
for (LodQuadTreeRegion[] regions : regions)
|
||||
for (LodQuadTree[] regions : regions)
|
||||
{
|
||||
if(regions == null)
|
||||
continue;
|
||||
|
||||
for (LodQuadTreeRegion region : regions)
|
||||
for (LodQuadTree region : regions)
|
||||
{
|
||||
if(region == null)
|
||||
continue;
|
||||
@@ -583,7 +587,7 @@ public class LodQuadTreeDimension
|
||||
width = newWidth;
|
||||
halfWidth = (int)Math.floor(width / 2);
|
||||
|
||||
regions = new LodQuadTreeRegion[width][width];
|
||||
regions = new LodQuadTree[width][width];
|
||||
isRegionDirty = new boolean[width][width];
|
||||
|
||||
// populate isRegionDirty
|
||||
|
||||
@@ -287,29 +287,37 @@ public class LodQuadTreeNode
|
||||
return lodDataPoint;
|
||||
}
|
||||
|
||||
public void combineData(List<LodQuadTreeNode> dataList){
|
||||
if(dataList.isEmpty()){
|
||||
public void combineData(List<LodQuadTreeNode> dataList)
|
||||
{
|
||||
if(dataList.isEmpty())
|
||||
{
|
||||
lodDataPoint = new LodDataPoint();
|
||||
}else {
|
||||
}
|
||||
else
|
||||
{
|
||||
short height = (short) dataList.stream().mapToInt(x -> (int) x.getLodDataPoint().height).min().getAsInt();
|
||||
short depth = (short) dataList.stream().mapToInt(x -> (int) x.getLodDataPoint().depth).max().getAsInt();
|
||||
int red= dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getRed()).sum()/dataList.size();
|
||||
int green= dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getGreen()).sum()/dataList.size();
|
||||
int red = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getRed()).sum()/dataList.size();
|
||||
int green = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getGreen()).sum()/dataList.size();
|
||||
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);
|
||||
|
||||
//the new complexity equal to the lowest complexity of the list
|
||||
DistanceGenerationMode minComplexity = DistanceGenerationMode.SERVER;
|
||||
for(LodQuadTreeNode node: dataList){
|
||||
if (minComplexity.compareTo(node.complexity) > 0){
|
||||
for(LodQuadTreeNode node: dataList)
|
||||
{
|
||||
if (minComplexity.compareTo(node.complexity) > 0)
|
||||
{
|
||||
minComplexity = node.complexity;
|
||||
}
|
||||
}
|
||||
|
||||
complexity = minComplexity;
|
||||
|
||||
voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0;
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
dontSave = false;
|
||||
}
|
||||
|
||||
@@ -1,482 +0,0 @@
|
||||
/*
|
||||
* This file is part of the LOD Mod, licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.seibel.lod.objects;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.seibel.lod.enums.DistanceGenerationMode;
|
||||
|
||||
/**
|
||||
* This object contains all data useful to render LodBlock in a region (32x32 chunk o 512x512 block)
|
||||
* for every node it contains the border of the block, the size, the position at it's level, the color, the height and the depth.
|
||||
*/
|
||||
public class LodQuadTreeRegion
|
||||
{
|
||||
//notes
|
||||
//The term node correspond to a LodQuadTree object
|
||||
|
||||
|
||||
/*
|
||||
Example on how it will be rendered (the number correspond to the level in the LodNodeData)
|
||||
.___.___._______._______________.
|
||||
|6|6| 7 | | |
|
||||
|6|6|___| 8 | |
|
||||
| 7 | 7 | | |
|
||||
|___|___|_______| 9 |
|
||||
| | | |
|
||||
| 8 | 8 | |
|
||||
| | | |
|
||||
|_______|_______|_______________|
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| 9 | 9 |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|_______________|_______________|
|
||||
*/
|
||||
//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 lodNode;
|
||||
/*
|
||||
.____.____.
|
||||
| NW | NE | |
|
||||
|____|____| Z
|
||||
| SW | SE | |
|
||||
|____|____| V
|
||||
-----X---->
|
||||
|
||||
North - negative z
|
||||
South - positive z
|
||||
West - negative x
|
||||
east - positive x
|
||||
*/
|
||||
|
||||
|
||||
//level completed is true if and only if all child are not null
|
||||
private boolean nodeFull;
|
||||
private boolean nodeEmpty;
|
||||
|
||||
//the four child based on the four diagonal cardinal direction
|
||||
//the first index is for N and S and the second index is for W and S
|
||||
//children should always be null for level 0.
|
||||
private final LodQuadTreeRegion[][] children;
|
||||
|
||||
//parent should always be null for level 9, and always not null for other levels.
|
||||
private final LodQuadTreeRegion parent;
|
||||
|
||||
/**
|
||||
* Constructor for level 0 without LodNodeData (region level constructor)
|
||||
*
|
||||
* @param regionX indicate the x region position of the node
|
||||
* @param regionZ indicate the z region position of the node
|
||||
*/
|
||||
//maybe the use of useLevelCoordinate could be changed. I could use a builder to do all this work.
|
||||
public LodQuadTreeRegion(int regionX, int regionZ)
|
||||
{
|
||||
this(null, new LodQuadTreeNode(LodQuadTreeNode.REGION_LEVEL, regionX, regionZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for generic level without LodNodeData
|
||||
*
|
||||
* @param parent parent of this node
|
||||
* @param level level of this note
|
||||
* @param posX position x in the level
|
||||
* @param posZ position z in the level
|
||||
*/
|
||||
public LodQuadTreeRegion(LodQuadTreeRegion parent, byte level, int posX, int posZ) {
|
||||
this(parent, new LodQuadTreeNode(level, posX, posZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for generic level via the LodNodeData
|
||||
*
|
||||
* @param lodNode object containing all the information of this node
|
||||
*/
|
||||
public LodQuadTreeRegion(LodQuadTreeRegion parent, LodQuadTreeNode lodNode) {
|
||||
this.parent = parent;
|
||||
this.lodNode = lodNode;
|
||||
this.children = new LodQuadTreeRegion[2][2];
|
||||
this.nodeEmpty = true;
|
||||
this.nodeFull = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using a dataList
|
||||
*
|
||||
* @param dataList list of LodNodeData to put in this LodQuadTree
|
||||
* @param regionX x region coordinate
|
||||
* @param regionZ z region coordinate
|
||||
*/
|
||||
public LodQuadTreeRegion(List<LodQuadTreeNode> dataList, int regionX, int regionZ) {
|
||||
this(null, new LodQuadTreeNode(LodQuadTreeNode.REGION_LEVEL, regionX, regionZ));
|
||||
this.setNodesAtLowerLevel(dataList, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param dataList list of data to put in the node
|
||||
* @param updateHigherLevel will update the color and height of higher level only if true
|
||||
*/
|
||||
public void setNodesAtLowerLevel(List<LodQuadTreeNode> dataList, boolean updateHigherLevel) {
|
||||
for (LodQuadTreeNode lodQuadTreeNode : dataList) {
|
||||
//this is slow, you could set update to false and use an only top down update method.
|
||||
this.setNodeAtLowerLevel(lodQuadTreeNode, updateHigherLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 newLodNode, boolean updateHigherLevel)
|
||||
{
|
||||
//check if we try to introduce a level that is higher or equal than the current one
|
||||
byte targetLevel = newLodNode.detailLevel;
|
||||
byte currentLevel = lodNode.detailLevel;
|
||||
if (targetLevel < currentLevel) {
|
||||
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);
|
||||
if (getChild(NS, WE) == null) {
|
||||
setChild(NS, WE);
|
||||
}
|
||||
LodQuadTreeRegion child = getChild(NS, WE);
|
||||
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(newLodNode, true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return child.setNodeAtLowerLevel(newLodNode, updateHigherLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chunkPosX
|
||||
* @param chunkPosZ
|
||||
* @param targetLevel
|
||||
* @return
|
||||
*/
|
||||
public LodQuadTreeNode getNodeAtChunkPos(int chunkPosX, int chunkPosZ, int targetLevel)
|
||||
{
|
||||
if (targetLevel > LodQuadTreeNode.REGION_LEVEL)
|
||||
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + targetLevel + "\" when \"" + LodQuadTreeNode.REGION_LEVEL + "\" is the max.");
|
||||
|
||||
byte currentLevel = lodNode.detailLevel;
|
||||
if (targetLevel == currentLevel)
|
||||
{
|
||||
return lodNode;
|
||||
}
|
||||
else if (targetLevel < currentLevel)
|
||||
{
|
||||
short widthRatio = (short) (lodNode.width / (2 * Math.pow(2, targetLevel)));
|
||||
int WE = Math.abs(Math.floorDiv(chunkPosX , widthRatio) % 2);
|
||||
int NS = Math.abs(Math.floorDiv(chunkPosZ , widthRatio) % 2);
|
||||
if (getChild(NS, WE) == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
LodQuadTreeRegion child = getChild(NS, WE);
|
||||
return child.getNodeAtChunkPos(chunkPosX, chunkPosZ, targetLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public LodQuadTreeRegion getChild(int NS, int WE)
|
||||
{
|
||||
return children[NS][WE];
|
||||
}
|
||||
|
||||
/**
|
||||
* setChild will put a child with given data in the given position
|
||||
*
|
||||
* @param newLodNode data to put in the child
|
||||
* @param NS North-South position
|
||||
* @param WE West-East position
|
||||
*/
|
||||
public void setChild(LodQuadTreeNode newLodNode, int NS, int WE) {
|
||||
if (newLodNode.detailLevel == lodNode.detailLevel - 1) {
|
||||
children[NS][WE] = new LodQuadTreeRegion(this, lodNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setChild will put a child with given data in the given position
|
||||
*
|
||||
* @param newLodNode data to put in the child
|
||||
*/
|
||||
public void setChild(LodQuadTreeNode newLodNode) {
|
||||
if (newLodNode.detailLevel == lodNode.detailLevel - 1) {
|
||||
int WE = newLodNode.posX % lodNode.posX;
|
||||
int NS = newLodNode.posZ % lodNode.posZ;
|
||||
children[NS][WE] = new LodQuadTreeRegion(this, lodNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setChild will put a child in the given position
|
||||
*
|
||||
* @param NS North-South position
|
||||
* @param WE West-East position
|
||||
*/
|
||||
public void setChild(int NS, int WE) {
|
||||
int childX = lodNode.posX * 2 + WE;
|
||||
int childZ = lodNode.posZ * 2 + NS;
|
||||
children[NS][WE] = new LodQuadTreeRegion(this, (byte) (lodNode.detailLevel - 1), childX, childZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update level update the level data such as levelFull and lodNodeData.
|
||||
*
|
||||
* @param recursiveUpdate if recursive is true the update will rise up to the level 0
|
||||
*/
|
||||
private void updateLevel(boolean recursiveUpdate) {
|
||||
boolean isFull = true;
|
||||
boolean isEmpty = true;
|
||||
List<LodQuadTreeNode> dataList = new ArrayList<>();
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
if (getChild(NS,WE) != null) {
|
||||
dataList.add(getChild(NS,WE).getLodNodeData());
|
||||
isEmpty = false;
|
||||
} else {
|
||||
isFull = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
nodeFull = isFull;
|
||||
nodeEmpty = isEmpty;
|
||||
lodNode.combineData(dataList);
|
||||
if (lodNode.detailLevel < 9 && recursiveUpdate) {
|
||||
this.parent.updateLevel(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* method to get certain nodes from the LodQuadTree
|
||||
*
|
||||
* @param complexityMask set of complexity to accept
|
||||
* @param getOnlyDirty if true it will return only dirty nodes
|
||||
* @param getOnlyLeaf if true it will return only leaf nodes
|
||||
* @return list of nodes
|
||||
*/
|
||||
public List<LodQuadTreeNode> getNodeListWithMask(Set<DistanceGenerationMode> complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf) {
|
||||
List<LodQuadTreeNode> nodeList = new ArrayList<>();
|
||||
if (isThereAnyChild()) {
|
||||
//There is at least 1 child
|
||||
if (!getOnlyLeaf
|
||||
&& !(getOnlyDirty && !lodNode.isDirty())
|
||||
&& complexityMask.contains(lodNode.getComplexity())) {
|
||||
nodeList.add(lodNode);
|
||||
}
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTreeRegion child = children[NS][WE];
|
||||
if (child != null) {
|
||||
nodeList.addAll(child.getNodeListWithMask(complexityMask, getOnlyDirty, getOnlyLeaf));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//There are no children
|
||||
if (!(getOnlyDirty && !lodNode.isDirty())
|
||||
&& (complexityMask.contains(lodNode.getComplexity()))){
|
||||
nodeList.add(lodNode);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return all the nodes that can be rendered based on the data given
|
||||
*
|
||||
* @param x position of the player
|
||||
* @param z position of the player
|
||||
* @param targetLevel minimum level that can be rendered
|
||||
* @param maxDistance maximum distance from the player
|
||||
* @param minDistance minimum distance from the player
|
||||
* @return
|
||||
*/
|
||||
public List<LodQuadTreeNode> getNodeToRender(int x, int z, int targetLevel, Set<DistanceGenerationMode> complexityMask, int maxDistance, int minDistance)
|
||||
{
|
||||
List<Integer> distances = new ArrayList<>();
|
||||
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<LodQuadTreeNode> nodeList = new ArrayList<>();
|
||||
|
||||
if (targetLevel <= lodNode.detailLevel && ((min <= maxDistance && max >= minDistance) /*|| isCoordinateInLevel(x, z)*/)) {
|
||||
if (targetLevel == lodNode.detailLevel || !isNodeFull()) {
|
||||
if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity())) {
|
||||
nodeList.add(lodNode);
|
||||
}
|
||||
} else {
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTreeRegion child = getChild(NS, WE);
|
||||
if (child != null) {
|
||||
nodeList.addAll(child.getNodeToRender(x, z, targetLevel, complexityMask, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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<AbstractMap.SimpleEntry<LodQuadTreeNode, Integer>> getNodesToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) {
|
||||
|
||||
List<Integer> distances = new ArrayList<>();
|
||||
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<AbstractMap.SimpleEntry<LodQuadTreeNode, Integer>> nodeList = new ArrayList<>();
|
||||
if (targetLevel <= lodNode.detailLevel && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) {
|
||||
if(!isThereAnyChild() || targetLevel == lodNode.detailLevel){
|
||||
if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0 ) {
|
||||
nodeList.add(new AbstractMap.SimpleEntry<LodQuadTreeNode, Integer>(this.lodNode, min));
|
||||
}
|
||||
}else {
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
if (getChild(NS, WE) == null) {
|
||||
setChild(NS, WE);
|
||||
}
|
||||
nodeList.addAll(getChild(NS, WE).getNodesToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* simple getter for lodNodeData
|
||||
*
|
||||
* @return lodNodeData
|
||||
*/
|
||||
public LodQuadTreeNode getLodNodeData() {
|
||||
return lodNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for lodNodeData, to maintain a correct relationship between level this method force update on all parent
|
||||
*
|
||||
* @param newLodQuadTreeNode data to set
|
||||
* @param updateHigherLevel if true it will update all the upper levels.
|
||||
*/
|
||||
public void setLodNodeData(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) {
|
||||
if (this.lodNode == null) {
|
||||
this.lodNode = newLodQuadTreeNode;
|
||||
} else {
|
||||
this.lodNode.update(newLodQuadTreeNode);
|
||||
}
|
||||
//a recursive update is necessary to change higher level
|
||||
if (parent != null && updateHigherLevel) parent.updateLevel(true);
|
||||
}
|
||||
|
||||
public boolean isNodeFull() {
|
||||
return nodeFull;
|
||||
}
|
||||
|
||||
public boolean isThereAnyChild() {
|
||||
return !nodeEmpty;
|
||||
}
|
||||
|
||||
public boolean isRenderable() {
|
||||
return (lodNode != null);
|
||||
}
|
||||
|
||||
|
||||
public boolean isCoordinateInLevel(int x, int z){
|
||||
return (lodNode.getStartX() * lodNode.width <= x && lodNode.getStartZ() * lodNode.width <= z && lodNode.getEndX() * lodNode.width >= x && lodNode.getEndZ() * lodNode.width >= z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
String s = lodNode.toString();
|
||||
return s;
|
||||
/*
|
||||
if(isThereAnyChild()){
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTree child = children[NS][WE];
|
||||
if (child != null) {
|
||||
s += '\n' + child.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
*/
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user