WorldOctTree small updates
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-11-11 11:11:41 -05:00
parent 4f2fcc62c9
commit 183c98367c
4 changed files with 98 additions and 82 deletions

View File

@ -14,7 +14,7 @@ import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.util.ds.octree.WorldOctTree;
import electrosphere.util.ds.octree.WorldOctTree.FloatingChunkTreeNode;
import electrosphere.util.ds.octree.WorldOctTree.WorldOctTreeNode;
import electrosphere.util.math.GeomUtils;
/**
@ -95,7 +95,7 @@ public class ClientDrawCellManager {
/**
* Tracks what nodes have been evaluated this frame -- used to deduplicate evaluation calls
*/
Map<FloatingChunkTreeNode<DrawCell>,Boolean> evaluationMap = new HashMap<FloatingChunkTreeNode<DrawCell>,Boolean>();
Map<WorldOctTreeNode<DrawCell>,Boolean> evaluationMap = new HashMap<WorldOctTreeNode<DrawCell>,Boolean>();
/**
* The last recorded player world position
@ -173,7 +173,7 @@ public class ClientDrawCellManager {
validCellCount = 0;
evaluationMap.clear();
//update all full res cells
FloatingChunkTreeNode<DrawCell> rootNode = this.chunkTree.getRoot();
WorldOctTreeNode<DrawCell> rootNode = this.chunkTree.getRoot();
Globals.profiler.beginCpuSample("ClientDrawCellManager.update - full res cells");
updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, SIXTEENTH_RES_LOD, distCache);
Globals.profiler.endCpuSample();
@ -217,7 +217,7 @@ public class ClientDrawCellManager {
* @param evaluationMap Map of leaf nodes that have been evaluated this frame
* @return true if there is work remaining to be done, false otherwise
*/
private boolean recursivelyUpdateCells(FloatingChunkTreeNode<DrawCell> node, Vector3i playerPos, Map<FloatingChunkTreeNode<DrawCell>,Boolean> evaluationMap, int minLeafLod, int distCache){
private boolean recursivelyUpdateCells(WorldOctTreeNode<DrawCell> node, Vector3i playerPos, Map<WorldOctTreeNode<DrawCell>,Boolean> evaluationMap, int minLeafLod, int distCache){
boolean updated = false;
if(evaluationMap.containsKey(node)){
return false;
@ -229,7 +229,7 @@ public class ClientDrawCellManager {
if(this.shouldSplit(playerPos, node, distCache)){
Globals.profiler.beginCpuSample("ClientDrawCellManager.split");
//perform op
FloatingChunkTreeNode<DrawCell> container = chunkTree.split(node);
WorldOctTreeNode<DrawCell> container = chunkTree.split(node);
//do deletions
this.twoLayerDestroy(node);
@ -300,7 +300,7 @@ public class ClientDrawCellManager {
if(this.shouldJoin(playerPos, node, distCache)) {
Globals.profiler.beginCpuSample("ClientDrawCellManager.join");
//perform op
FloatingChunkTreeNode<DrawCell> newLeaf = chunkTree.join(node);
WorldOctTreeNode<DrawCell> newLeaf = chunkTree.join(node);
//do deletions
this.twoLayerDestroy(node);
@ -317,9 +317,9 @@ public class ClientDrawCellManager {
updated = true;
} else {
this.validCellCount++;
List<FloatingChunkTreeNode<DrawCell>> children = node.getChildren();
List<WorldOctTreeNode<DrawCell>> children = node.getChildren();
for(int i = 0; i < 8; i++){
FloatingChunkTreeNode<DrawCell> child = children.get(i);
WorldOctTreeNode<DrawCell> child = children.get(i);
boolean childUpdate = recursivelyUpdateCells(child, playerPos, evaluationMap, minLeafLod, distCache);
if(childUpdate == true){
updated = true;
@ -339,7 +339,7 @@ public class ClientDrawCellManager {
* @param node the node
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, FloatingChunkTreeNode<DrawCell> node, int distCache){
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<DrawCell> node, int distCache){
if(node.getData() == null){
return GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
} else {
@ -388,7 +388,7 @@ public class ClientDrawCellManager {
* @param node The node
* @return true if should split, false otherwise
*/
public boolean shouldSplit(Vector3i pos, FloatingChunkTreeNode<DrawCell> node, int distCache){
public boolean shouldSplit(Vector3i pos, WorldOctTreeNode<DrawCell> node, int distCache){
//breaking out into dedicated function so can add case handling ie if we want
//to combine fullres nodes into larger nodes to conserve on draw calls
return
@ -430,7 +430,7 @@ public class ClientDrawCellManager {
* @param node The node to consider
* @return -1 if outside of render range, -1 if the node is not a valid draw cell leaf, otherwise returns the LOD level
*/
private int getLODLevel(FloatingChunkTreeNode<DrawCell> node){
private int getLODLevel(WorldOctTreeNode<DrawCell> node){
return this.chunkTree.getMaxLevel() - node.getLevel();
}
@ -440,7 +440,7 @@ public class ClientDrawCellManager {
* @param playerWorldPos The player's world position
* @return true if should solve for high res faces, false otherwise
*/
private boolean shouldSolveFaces(FloatingChunkTreeNode<DrawCell> node, Vector3i playerWorldPos, int distCache){
private boolean shouldSolveFaces(WorldOctTreeNode<DrawCell> node, Vector3i playerWorldPos, int distCache){
if(node.getLevel() == this.chunkTree.getMaxLevel()){
return false;
}
@ -472,7 +472,7 @@ public class ClientDrawCellManager {
* @param node The node for the chunk
* @return The face if there is a higher resolution face, null otherwise
*/
private List<DrawCellFace> solveHighResFace(FloatingChunkTreeNode<DrawCell> node){
private List<DrawCellFace> solveHighResFace(WorldOctTreeNode<DrawCell> node){
//don't bother to check if it's a full res chunk
if(node.getLevel() == this.chunkTree.getMaxLevel()){
return null;
@ -484,37 +484,37 @@ public class ClientDrawCellManager {
int spacing = (int)Math.pow(2,lodMultiplitier);
List<DrawCellFace> faces = new LinkedList<DrawCellFace>();
if(node.getMinBound().x - 1 >= 0){
FloatingChunkTreeNode<DrawCell> xNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(-1,1,1), false);
WorldOctTreeNode<DrawCell> xNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(-1,1,1), false);
if(xNegNode != null && xNegNode.getLevel() > node.getLevel()){
faces.add(DrawCellFace.X_NEGATIVE);
}
}
if(node.getMinBound().y - 1 >= 0){
FloatingChunkTreeNode<DrawCell> yNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,-1,1), false);
WorldOctTreeNode<DrawCell> yNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,-1,1), false);
if(yNegNode != null && yNegNode.getLevel() > node.getLevel()){
faces.add(DrawCellFace.Y_NEGATIVE);
}
}
if(node.getMinBound().z - 1 >= 0){
FloatingChunkTreeNode<DrawCell> zNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,1,-1), false);
WorldOctTreeNode<DrawCell> zNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,1,-1), false);
if(zNegNode != null && zNegNode.getLevel() > node.getLevel()){
faces.add(DrawCellFace.Z_NEGATIVE);
}
}
if(node.getMaxBound().x + spacing + 1 < this.worldDim){
FloatingChunkTreeNode<DrawCell> xPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(spacing + 1,1,1), false);
WorldOctTreeNode<DrawCell> xPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(spacing + 1,1,1), false);
if(xPosNode != null && xPosNode.getLevel() > node.getLevel()){
faces.add(DrawCellFace.X_POSITIVE);
}
}
if(node.getMaxBound().y + spacing + 1 < this.worldDim){
FloatingChunkTreeNode<DrawCell> yPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,spacing + 1,1), false);
WorldOctTreeNode<DrawCell> yPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,spacing + 1,1), false);
if(yPosNode != null && yPosNode.getLevel() > node.getLevel()){
faces.add(DrawCellFace.Y_POSITIVE);
}
}
if(node.getMaxBound().z + spacing + 1 < this.worldDim){
FloatingChunkTreeNode<DrawCell> zPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,1,spacing + 1), false);
WorldOctTreeNode<DrawCell> zPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,1,spacing + 1), false);
if(zPosNode != null && zPosNode.getLevel() > node.getLevel()){
faces.add(DrawCellFace.Z_POSITIVE);
}
@ -530,43 +530,43 @@ public class ClientDrawCellManager {
* @param node The node to search from adjacencies from
* @param level The level to check against
*/
private void conditionalUpdateAdjacentNodes(FloatingChunkTreeNode<DrawCell> node, int level){
private void conditionalUpdateAdjacentNodes(WorldOctTreeNode<DrawCell> node, int level){
//don't bother to check if it's a lowest-res chunk
if(this.chunkTree.getMaxLevel() - level > ClientDrawCellManager.FULL_RES_LOD){
return;
}
if(node.getMinBound().x - 1 >= 0){
FloatingChunkTreeNode<DrawCell> xNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(-1,0,0), false);
WorldOctTreeNode<DrawCell> xNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(-1,0,0), false);
if(xNegNode != null && xNegNode.getLevel() < level){
xNegNode.getData().setHasGenerated(false);
}
}
if(node.getMinBound().y - 1 >= 0){
FloatingChunkTreeNode<DrawCell> yNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(0,-1,0), false);
WorldOctTreeNode<DrawCell> yNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(0,-1,0), false);
if(yNegNode != null && yNegNode.getLevel() < level){
yNegNode.getData().setHasGenerated(false);
}
}
if(node.getMinBound().z - 1 >= 0){
FloatingChunkTreeNode<DrawCell> zNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(0,0,-1), false);
WorldOctTreeNode<DrawCell> zNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(0,0,-1), false);
if(zNegNode != null && zNegNode.getLevel() < level){
zNegNode.getData().setHasGenerated(false);
}
}
if(node.getMaxBound().x + 1 < this.worldDim){
FloatingChunkTreeNode<DrawCell> xPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(1,-1,-1), false);
WorldOctTreeNode<DrawCell> xPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(1,-1,-1), false);
if(xPosNode != null && xPosNode.getLevel() < level){
xPosNode.getData().setHasGenerated(false);
}
}
if(node.getMaxBound().y + 1 < this.worldDim){
FloatingChunkTreeNode<DrawCell> yPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(-1,1,-1), false);
WorldOctTreeNode<DrawCell> yPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(-1,1,-1), false);
if(yPosNode != null && yPosNode.getLevel() < level){
yPosNode.getData().setHasGenerated(false);
}
}
if(node.getMaxBound().z + 1 < this.worldDim){
FloatingChunkTreeNode<DrawCell> zPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(-1,-1,1), false);
WorldOctTreeNode<DrawCell> zPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(-1,-1,1), false);
if(zPosNode != null && zPosNode.getLevel() < level){
zPosNode.getData().setHasGenerated(false);
}
@ -579,7 +579,7 @@ public class ClientDrawCellManager {
* @param node The node
* @return true if should be joined, false otherwise
*/
public boolean shouldJoin(Vector3i pos, FloatingChunkTreeNode<DrawCell> node, int distCache){
public boolean shouldJoin(Vector3i pos, WorldOctTreeNode<DrawCell> node, int distCache){
//breaking out into dedicated function so can add case handling ie if we want
//to combine fullres nodes into larger nodes to conserve on draw calls
return
@ -620,7 +620,7 @@ public class ClientDrawCellManager {
* @param minLeafLod The minimum LOD required to evaluate a leaf
* @return true if should request chunk data, false otherwise
*/
public boolean shouldRequest(Vector3i pos, FloatingChunkTreeNode<DrawCell> node, int minLeafLod, int distCache){
public boolean shouldRequest(Vector3i pos, WorldOctTreeNode<DrawCell> node, int minLeafLod, int distCache){
return
node.getData() != null &&
!node.getData().hasRequested() &&
@ -666,7 +666,7 @@ public class ClientDrawCellManager {
* @param minLeafLod The minimum LOD required to evaluate a leaf
* @return true if should generate, false otherwise
*/
public boolean shouldGenerate(Vector3i pos, FloatingChunkTreeNode<DrawCell> node, int minLeafLod, int distCache){
public boolean shouldGenerate(Vector3i pos, WorldOctTreeNode<DrawCell> node, int minLeafLod, int distCache){
return
node.getData() != null &&
!node.getData().hasGenerated() &&
@ -710,7 +710,7 @@ public class ClientDrawCellManager {
* @param node The node
* @return true if should destroy, false otherwise
*/
public boolean shouldDestroy(FloatingChunkTreeNode<DrawCell> node){
public boolean shouldDestroy(WorldOctTreeNode<DrawCell> node){
return
node.getData() != null &&
node.getData().getEntity() != null
@ -728,7 +728,7 @@ public class ClientDrawCellManager {
* Recursively destroy a tree
* @param node The root of the tree
*/
private void recursivelyDestroy(FloatingChunkTreeNode<DrawCell> node){
private void recursivelyDestroy(WorldOctTreeNode<DrawCell> node){
if(node.getChildren().size() > 0){
node.getChildren().forEach(child -> recursivelyDestroy(child));
}
@ -741,9 +741,9 @@ public class ClientDrawCellManager {
* Destroys two layers of nodes
* @param node The top node
*/
private void twoLayerDestroy(FloatingChunkTreeNode<DrawCell> node){
private void twoLayerDestroy(WorldOctTreeNode<DrawCell> node){
if(node.getData() == null){
for(FloatingChunkTreeNode<DrawCell> child : node.getChildren()){
for(WorldOctTreeNode<DrawCell> child : node.getChildren()){
if(child.getData() != null){
child.getData().destroy();
}
@ -797,7 +797,7 @@ public class ClientDrawCellManager {
* @param cell The cell
* @return true if all cells were successfully requested, false otherwise
*/
private boolean requestChunks(WorldOctTree.FloatingChunkTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
private boolean requestChunks(WorldOctTree.WorldOctTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
DrawCell cell = node.getData();
int lod = this.chunkTree.getMaxLevel() - node.getLevel();
int spacingFactor = (int)Math.pow(2,lod);
@ -873,7 +873,7 @@ public class ClientDrawCellManager {
* @param highResFace The higher resolution face of a not-full-resolution chunk. Null if the chunk is max resolution or there is no higher resolution face for the current chunk
* @return true if all data is available, false otherwise
*/
private boolean containsDataToGenerate(WorldOctTree.FloatingChunkTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
private boolean containsDataToGenerate(WorldOctTree.WorldOctTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
DrawCell cell = node.getData();
int lod = this.chunkTree.getMaxLevel() - node.getLevel();
int spacingFactor = (int)Math.pow(2,lod);
@ -966,7 +966,7 @@ public class ClientDrawCellManager {
* Recursively calculates the status of the manager
* @param node The root node
*/
private void recursivelyCalculateStatus(FloatingChunkTreeNode<DrawCell> node){
private void recursivelyCalculateStatus(WorldOctTreeNode<DrawCell> node){
if(node.getLevel() == this.chunkTree.getMaxLevel() - 1){
halfResCount++;
}
@ -977,8 +977,8 @@ public class ClientDrawCellManager {
generated++;
}
if(node.getChildren() != null && node.getChildren().size() > 0){
List<FloatingChunkTreeNode<DrawCell>> children = new LinkedList<FloatingChunkTreeNode<DrawCell>>(node.getChildren());
for(FloatingChunkTreeNode<DrawCell> child : children){
List<WorldOctTreeNode<DrawCell>> children = new LinkedList<WorldOctTreeNode<DrawCell>>(node.getChildren());
for(WorldOctTreeNode<DrawCell> child : children){
recursivelyCalculateStatus(child);
}
}
@ -1024,7 +1024,7 @@ public class ClientDrawCellManager {
* @return The draw cell if it exists, null otherwise
*/
public DrawCell getDrawCell(int worldX, int worldY, int worldZ){
FloatingChunkTreeNode<DrawCell> node = this.chunkTree.search(new Vector3i(worldX,worldY,worldZ), false);
WorldOctTreeNode<DrawCell> node = this.chunkTree.search(new Vector3i(worldX,worldY,worldZ), false);
if(node != null){
return node.getData();
}

View File

@ -15,7 +15,7 @@ import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.util.ds.octree.WorldOctTree.FloatingChunkTreeNode;
import electrosphere.util.ds.octree.WorldOctTree.WorldOctTreeNode;
import electrosphere.util.math.GeomUtils;
/**
@ -536,7 +536,7 @@ public class DrawCell {
* @param distCache the lod value under which distance caches are invalidated
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, FloatingChunkTreeNode<DrawCell> node, int distCache){
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<DrawCell> node, int distCache){
if(cachedMinDistance != INVALID_DIST_CACHE && distCache < lod){
return cachedMinDistance;
} else {

View File

@ -21,12 +21,12 @@ public class WorldOctTree <T> {
/**
* The root node
*/
private FloatingChunkTreeNode<T> root = null;
private WorldOctTreeNode<T> root = null;
/**
* The list of all nodes in the tree
*/
List<FloatingChunkTreeNode<T>> nodes = null;
List<WorldOctTreeNode<T>> nodes = null;
/**
* The minimum position
@ -60,8 +60,8 @@ public class WorldOctTree <T> {
//calculate max level
int dimRaw = max.x - min.x;
this.maxLevel = (int)MathUtils.log2(dimRaw);
this.nodes = new ArrayList<FloatingChunkTreeNode<T>>();
this.root = new FloatingChunkTreeNode<T>(this, 0, new Vector3i(min), new Vector3i(max));
this.nodes = new ArrayList<WorldOctTreeNode<T>>();
this.root = new WorldOctTreeNode<T>(this, 0, new Vector3i(min), new Vector3i(max));
this.root.isLeaf = true;
this.nodes.add(this.root);
}
@ -71,7 +71,7 @@ public class WorldOctTree <T> {
* @param parent The parent
* @return The new non-leaf node
*/
public FloatingChunkTreeNode<T> split(FloatingChunkTreeNode<T> existing){
public WorldOctTreeNode<T> split(WorldOctTreeNode<T> existing){
if(!existing.isLeaf()){
throw new IllegalArgumentException("Tried to split non-leaf!");
}
@ -81,20 +81,20 @@ public class WorldOctTree <T> {
int midY = (max.y - min.y) / 2 + min.y;
int midZ = (max.z - min.z) / 2 + min.z;
int currentLevel = existing.getLevel();
FloatingChunkTreeNode<T> newContainer = new FloatingChunkTreeNode<>(this, currentLevel, min, max);
WorldOctTreeNode<T> newContainer = new WorldOctTreeNode<>(this, currentLevel, min, max);
//add children
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,min.y,min.z), new Vector3i(midX,midY,midZ)));
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,min.y,min.z), new Vector3i(max.x,midY,midZ)));
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,midY,min.z), new Vector3i(midX,max.y,midZ)));
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,midY,min.z), new Vector3i(max.x,max.y,midZ)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,min.y,min.z), new Vector3i(midX,midY,midZ)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,min.y,min.z), new Vector3i(max.x,midY,midZ)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,midY,min.z), new Vector3i(midX,max.y,midZ)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,midY,min.z), new Vector3i(max.x,max.y,midZ)));
//
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,min.y,midZ), new Vector3i(midX,midY,max.z)));
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,min.y,midZ), new Vector3i(max.x,midY,max.z)));
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,midY,midZ), new Vector3i(midX,max.y,max.z)));
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,midY,midZ), new Vector3i(max.x,max.y,max.z)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,min.y,midZ), new Vector3i(midX,midY,max.z)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,min.y,midZ), new Vector3i(max.x,midY,max.z)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,midY,midZ), new Vector3i(midX,max.y,max.z)));
newContainer.addChild(new WorldOctTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,midY,midZ), new Vector3i(max.x,max.y,max.z)));
boolean foundMin = false;
for(FloatingChunkTreeNode<T> child : newContainer.getChildren()){
for(WorldOctTreeNode<T> child : newContainer.getChildren()){
if(child.getMinBound().distance(newContainer.getMinBound()) == 0){
foundMin = true;
}
@ -104,7 +104,7 @@ public class WorldOctTree <T> {
message = message + min + " " + max + "\n";
message = message + midX + " " + midY + " " + midZ + "\n";
message = message + "container mid: " + newContainer.getMinBound();
for(FloatingChunkTreeNode<T> child : newContainer.getChildren()){
for(WorldOctTreeNode<T> child : newContainer.getChildren()){
message = message + "child min: " + child.getMinBound() + "\n";
}
throw new Error(message);
@ -126,14 +126,14 @@ public class WorldOctTree <T> {
* @param parent The non-leaf
* @return The new leaf node
*/
public FloatingChunkTreeNode<T> join(FloatingChunkTreeNode<T> existing){
public WorldOctTreeNode<T> join(WorldOctTreeNode<T> existing){
if(existing.isLeaf()){
throw new IllegalArgumentException("Tried to split non-leaf!");
}
Vector3i min = existing.getMinBound();
Vector3i max = existing.getMaxBound();
int currentLevel = existing.getLevel();
FloatingChunkTreeNode<T> newContainer = new FloatingChunkTreeNode<>(this, currentLevel, min, max);
WorldOctTreeNode<T> newContainer = new WorldOctTreeNode<>(this, currentLevel, min, max);
//replace existing node
this.replaceNode(existing,newContainer);
@ -151,11 +151,11 @@ public class WorldOctTree <T> {
* @param existing the existing node
* @param newNode the new node
*/
private void replaceNode(FloatingChunkTreeNode<T> existing, FloatingChunkTreeNode<T> newNode){
private void replaceNode(WorldOctTreeNode<T> existing, WorldOctTreeNode<T> newNode){
if(existing == this.root){
this.root = newNode;
} else {
FloatingChunkTreeNode<T> parent = existing.getParent();
WorldOctTreeNode<T> parent = existing.getParent();
int index = parent.children.indexOf(existing);
parent.removeChild(existing);
parent.addChild(index, newNode);
@ -165,7 +165,7 @@ public class WorldOctTree <T> {
/**
* Gets the root node of the tree
*/
public FloatingChunkTreeNode<T> getRoot() {
public WorldOctTreeNode<T> getRoot() {
return this.root;
}
@ -190,7 +190,7 @@ public class WorldOctTree <T> {
*/
public void clear(){
this.nodes.clear();
this.root = new FloatingChunkTreeNode<T>(this, 0, new Vector3i(min), new Vector3i(max));
this.root = new WorldOctTreeNode<T>(this, 0, new Vector3i(min), new Vector3i(max));
this.root.isLeaf = true;
this.nodes.add(this.root);
}
@ -201,7 +201,7 @@ public class WorldOctTree <T> {
* @param returnNonLeaf If true, the function can return non-leaf nodes, otherwise will only return leaf nodes
* @return The leaf if it exists, null otherwise
*/
public FloatingChunkTreeNode<T> search(Vector3i position, boolean returnNonLeaf){
public WorldOctTreeNode<T> search(Vector3i position, boolean returnNonLeaf){
return this.search(position,returnNonLeaf,this.maxLevel);
}
@ -212,7 +212,7 @@ public class WorldOctTree <T> {
* @param maxLevel The maximum level to search for
* @return The leaf if it exists, null otherwise
*/
public FloatingChunkTreeNode<T> search(Vector3i position, boolean returnNonLeaf, int maxLevel){
public WorldOctTreeNode<T> search(Vector3i position, boolean returnNonLeaf, int maxLevel){
//out of bounds check
if(
position.x < min.x || position.x > max.x ||
@ -221,7 +221,7 @@ public class WorldOctTree <T> {
){
throw new Error("Trying to search for node outside tree range!");
}
FloatingChunkTreeNode<T> searchResult = recursiveSearchUnsafe(root,position,maxLevel);
WorldOctTreeNode<T> searchResult = recursiveSearchUnsafe(root,position,maxLevel);
if(!returnNonLeaf && !searchResult.isLeaf()){
return null;
}
@ -235,7 +235,7 @@ public class WorldOctTree <T> {
* @param maxLevel The maximum level to search for
* @return The found node
*/
private FloatingChunkTreeNode<T> recursiveSearchUnsafe(FloatingChunkTreeNode<T> currentNode, Vector3i position, int maxLevel){
private WorldOctTreeNode<T> recursiveSearchUnsafe(WorldOctTreeNode<T> currentNode, Vector3i position, int maxLevel){
if(maxLevel < 0){
throw new Error("Provided invalid max level! Must be created than 0! " + maxLevel);
}
@ -246,7 +246,7 @@ public class WorldOctTree <T> {
return currentNode;
}
if(currentNode.getChildren().size() > 0){
for(FloatingChunkTreeNode<T> child : currentNode.getChildren()){
for(WorldOctTreeNode<T> child : currentNode.getChildren()){
if(
position.x < child.getMaxBound().x && position.x >= child.getMinBound().x &&
position.y < child.getMaxBound().y && position.y >= child.getMinBound().y &&
@ -258,7 +258,7 @@ public class WorldOctTree <T> {
String message = "Current node is within range, but no children are! This does not make any sense.\n";
message = message + " current pos: " + currentNode.getMinBound() + " " + currentNode.getMaxBound() + "\n";
for(FloatingChunkTreeNode<T> child : currentNode.getChildren()){
for(WorldOctTreeNode<T> child : currentNode.getChildren()){
message = message + " child " + child + " pos: " + child.getMinBound() + " " + child.getMaxBound() + "\n";
}
message = message + "position to search: " + position + "\n";
@ -272,13 +272,13 @@ public class WorldOctTree <T> {
/**
* A node in a chunk tree
*/
public static class FloatingChunkTreeNode<T> {
public static class WorldOctTreeNode<T> {
//True if this is a leaf node, false otherwise
private boolean isLeaf;
//the parent node
private FloatingChunkTreeNode<T> parent;
private WorldOctTreeNode<T> parent;
/**
* The tree containing this node
@ -286,7 +286,7 @@ public class WorldOctTree <T> {
private WorldOctTree<T> containingTree;
//the children of this node
private List<FloatingChunkTreeNode<T>> children = new LinkedList<FloatingChunkTreeNode<T>>();
private List<WorldOctTreeNode<T>> children = new LinkedList<WorldOctTreeNode<T>>();
//The data at the node
private T data;
@ -314,7 +314,7 @@ public class WorldOctTree <T> {
* @param min The minimum position of the node
* @param max The maximum position of then ode
*/
private FloatingChunkTreeNode(WorldOctTree<T> tree, int level, Vector3i min, Vector3i max){
private WorldOctTreeNode(WorldOctTree<T> tree, int level, Vector3i min, Vector3i max){
if(tree == null){
throw new Error("Invalid tree provided " + tree);
}
@ -340,8 +340,8 @@ public class WorldOctTree <T> {
* @param max The max point
* @return The node
*/
public static <T> FloatingChunkTreeNode<T> constructorForTests(WorldOctTree<T> tree, int level, Vector3i min, Vector3i max){
return new FloatingChunkTreeNode<T>(tree, level, min, max);
public static <T> WorldOctTreeNode<T> constructorForTests(WorldOctTree<T> tree, int level, Vector3i min, Vector3i max){
return new WorldOctTreeNode<T>(tree, level, min, max);
}
/**
@ -353,6 +353,22 @@ public class WorldOctTree <T> {
this.data = data;
}
/**
* Sets whether this node is a leaf or not
* @param isLeaf true if it is a leaf, false otherwise
*/
public void setLeaf(boolean isLeaf){
this.isLeaf = isLeaf;
}
/**
* Sets the data of the node
* @param data The data
*/
public void setData(T data){
this.data = data;
}
/**
* Gets the data associated with this node
*/
@ -363,14 +379,14 @@ public class WorldOctTree <T> {
/**
* Gets the parent of this node
*/
public FloatingChunkTreeNode<T> getParent() {
public WorldOctTreeNode<T> getParent() {
return parent;
}
/**
* Gets the children of this node
*/
public List<FloatingChunkTreeNode<T>> getChildren() {
public List<WorldOctTreeNode<T>> getChildren() {
return Collections.unmodifiableList(this.children);
}
@ -418,7 +434,7 @@ public class WorldOctTree <T> {
* Adds a child to this node
* @param child The child
*/
private void addChild(FloatingChunkTreeNode<T> child){
private void addChild(WorldOctTreeNode<T> child){
this.children.add(child);
child.parent = this;
}
@ -428,7 +444,7 @@ public class WorldOctTree <T> {
* @param index The index of the child
* @param child The child
*/
private void addChild(int index, FloatingChunkTreeNode<T> child){
private void addChild(int index, WorldOctTreeNode<T> child){
this.children.add(index, child);
child.parent = this;
}
@ -437,7 +453,7 @@ public class WorldOctTree <T> {
* Removes a child node
* @param child the child
*/
private void removeChild(FloatingChunkTreeNode<T> child){
private void removeChild(WorldOctTreeNode<T> child){
this.children.remove(child);
child.parent = null;
}

View File

@ -12,7 +12,7 @@ import electrosphere.engine.Main;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.test.annotations.UnitTest;
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
import electrosphere.util.ds.octree.WorldOctTree.FloatingChunkTreeNode;
import electrosphere.util.ds.octree.WorldOctTree.WorldOctTreeNode;
/**
* Tests for the client draw cell manager
@ -39,7 +39,7 @@ public class ClientDrawCellManagerTests {
ClientDrawCellManager manager = new ClientDrawCellManager(null, 64);
double precomputedMidDist = 0;
Vector3i playerPos = new Vector3i(0,0,0);
FloatingChunkTreeNode<DrawCell> node = FloatingChunkTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));
WorldOctTreeNode<DrawCell> node = WorldOctTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));
node.convertToLeaf(DrawCell.generateTerrainCell(new Vector3i(0,0,0),3));
assertTrue(manager.shouldSplit(playerPos, node, 0));