Fix world gen queue and rendering for new QuadTree Iterators
This commit is contained in:
@@ -9,6 +9,7 @@ import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.generation.tasks.*;
|
||||
import com.seibel.lod.core.pos.*;
|
||||
import com.seibel.lod.core.util.ThreadUtil;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadTree;
|
||||
import com.seibel.lod.core.util.objects.UncheckedInterruptedException;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
@@ -20,8 +21,6 @@ import org.apache.logging.log4j.Logger;
|
||||
import java.io.Closeable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class WorldGenerationQueue implements Closeable
|
||||
@@ -123,7 +122,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
if (this.waitingTaskQuadTree.isSectionPosInBounds(requestPos))
|
||||
{
|
||||
CompletableFuture<WorldGenResult> future = new CompletableFuture<>();
|
||||
this.waitingTaskQuadTree.set(requestPos, new WorldGenTask(pos, requiredDataDetail, tracker, future));
|
||||
this.waitingTaskQuadTree.setValue(requestPos, new WorldGenTask(pos, requiredDataDetail, tracker, future));
|
||||
return future;
|
||||
}
|
||||
else
|
||||
@@ -241,73 +240,28 @@ public class WorldGenerationQueue implements Closeable
|
||||
*/
|
||||
private boolean startNextWorldGenTask(DhBlockPos2D targetPos)
|
||||
{
|
||||
final AtomicReference<WorldGenTask> closestTaskRef = new AtomicReference<>(null);
|
||||
long closestGenDist = Long.MAX_VALUE;
|
||||
|
||||
// TODO improve
|
||||
this.waitingTaskQuadTree.forEachRootNode((rootQuadNode) ->
|
||||
WorldGenTask closestTask = null;
|
||||
|
||||
// TODO improve, having to go over every item isn't super efficient
|
||||
Iterator<QuadNode<WorldGenTask>> leafNodeIterator = this.waitingTaskQuadTree.leafNodeIterator();
|
||||
while (leafNodeIterator.hasNext())
|
||||
{
|
||||
if (closestTaskRef.get() == null)
|
||||
WorldGenTask newGenTask = leafNodeIterator.next().value;
|
||||
if (newGenTask != null) // TODO add an option to skip leaves with null values and potentially auto-prune them
|
||||
{
|
||||
rootQuadNode.forAllLeafValues((worldGenTask) ->
|
||||
|
||||
// use chebyShev distance in order to generate in rings around the target pos (also because it is a fast distance calculation)
|
||||
int chebDistToTargetPos = newGenTask.pos.getCenterBlockPos().toPos2D().chebyshevDist(targetPos.toPos2D());
|
||||
if (chebDistToTargetPos < closestGenDist)
|
||||
{
|
||||
if (closestTaskRef.get() == null)
|
||||
{
|
||||
closestTaskRef.set(worldGenTask);
|
||||
}
|
||||
});
|
||||
// this task is closer than the last one
|
||||
closestTask = newGenTask;
|
||||
closestGenDist = chebDistToTargetPos;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
WorldGenTask closestTask = closestTaskRef.get();
|
||||
|
||||
|
||||
// // look through the tree from lowest to highest detail level to find the next task to generate
|
||||
// for (byte detailLevel = QuadTree.TREE_LOWEST_DETAIL_LEVEL; detailLevel < this.waitingTaskQuadTree.treeMaxDetailLevel; detailLevel++)
|
||||
// {
|
||||
// // look for the task that is closest to the targetPos
|
||||
// long closestGenDist = Long.MAX_VALUE;
|
||||
//
|
||||
// MovableGridRingList<WorldGenTask> gridRingList = this.waitingTaskQuadTree.getRingList(detailLevel);
|
||||
// for (WorldGenTask newGenTask : gridRingList)
|
||||
// {
|
||||
// if (newGenTask != null)
|
||||
// {
|
||||
// if (queueFirstGenerationRequestFound)
|
||||
// {
|
||||
// // queue the first task we can find
|
||||
// closestTask = newGenTask;
|
||||
// break;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // use chebyShev distance in order to generate in rings around the target pos (also because it is a fast distance calculation)
|
||||
// int chebDistToTargetPos = newGenTask.pos.getCenterBlockPos().toPos2D().chebyshevDist(targetPos.toPos2D());
|
||||
// if (chebDistToTargetPos < closestGenDist)
|
||||
// {
|
||||
// // this task is closer than the last one
|
||||
// closestTask = newGenTask;
|
||||
// closestGenDist = chebDistToTargetPos;
|
||||
// }
|
||||
// else if (closestTask != null)
|
||||
// {
|
||||
// // this task is farther than the last one,
|
||||
// // assume we have gotten as close as we can
|
||||
// // and queue the task
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // a task has been found, don't look at the next detail level,
|
||||
// // everything there will be farther away
|
||||
// if (closestTask != null)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (closestTask == null)
|
||||
{
|
||||
@@ -318,7 +272,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
|
||||
// remove the task we found, we are going to start it and don't want to run it multiple times
|
||||
WorldGenTask removedWorldGenTask = this.waitingTaskQuadTree.set(new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z), null);
|
||||
WorldGenTask removedWorldGenTask = this.waitingTaskQuadTree.setValue(new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z), null);
|
||||
// removedWorldGenTask can be null // TODO when?
|
||||
|
||||
|
||||
@@ -366,9 +320,9 @@ public class WorldGenerationQueue implements Closeable
|
||||
childFutures.add(newFuture);
|
||||
|
||||
WorldGenTask newGenTask = new WorldGenTask(new DhLodPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ), childDhSectionPos.sectionDetailLevel, removedWorldGenTask.taskTracker, newFuture);
|
||||
this.waitingTaskQuadTree.set(new DhSectionPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ), newGenTask);
|
||||
this.waitingTaskQuadTree.setValue(new DhSectionPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ), newGenTask);
|
||||
|
||||
boolean valueAdded = this.waitingTaskQuadTree.get(new DhSectionPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ)) != null;
|
||||
boolean valueAdded = this.waitingTaskQuadTree.getValue(new DhSectionPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ)) != null;
|
||||
LodUtil.assertTrue(valueAdded); // failed to add world gen task to quad tree, this means the quad tree was the wrong size
|
||||
|
||||
// LOGGER.info("split feature "+sectionPos+" into "+childDhSectionPos+" "+(valueAdded ? "added" : "notAdded"));
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.seibel.lod.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadTree;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This quadTree structure is our core data structure and holds
|
||||
* all rendering data. <br><br>
|
||||
@@ -82,8 +84,8 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
* @param z z coordinate of the section
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodRenderSection getSection(byte detailLevel, int x, int z) { return this.get(new DhSectionPos(detailLevel, x, z)); }
|
||||
public LodRenderSection getSection(DhSectionPos pos) { return this.get(pos); }
|
||||
public LodRenderSection getSection(byte detailLevel, int x, int z) { return this.getValue(new DhSectionPos(detailLevel, x, z)); }
|
||||
public LodRenderSection getSection(DhSectionPos pos) { return this.getValue(pos); }
|
||||
|
||||
|
||||
|
||||
@@ -163,21 +165,34 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
}
|
||||
private void updateAllRenderSections(DhBlockPos2D playerPos)
|
||||
{
|
||||
this.forEachRootNodePos((rootNode, rootSectionPos) ->
|
||||
// make sure all root nodes are created
|
||||
Iterator<DhSectionPos> rootPosIterator = this.rootNodePosIterator();
|
||||
while (rootPosIterator.hasNext())
|
||||
{
|
||||
if (rootNode == null)
|
||||
DhSectionPos rootSectionPos = rootPosIterator.next();
|
||||
if (this.getNode(rootSectionPos) == null)
|
||||
{
|
||||
LodRenderSection newRenderSection = new LodRenderSection(rootSectionPos);
|
||||
this.set(rootSectionPos, newRenderSection);
|
||||
return; // update next tick
|
||||
this.setValue(rootSectionPos, newRenderSection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update all nodes in the tree
|
||||
Iterator<DhSectionPos> rootNodeIterator = this.rootNodePosIterator();
|
||||
while (rootNodeIterator.hasNext())
|
||||
{
|
||||
DhSectionPos rootPos = rootNodeIterator.next();
|
||||
QuadNode<LodRenderSection> rootNode = this.getNode(rootPos); // should never be null
|
||||
|
||||
|
||||
rootNode.forEachDirectChildNode((quadNode, sectionPos) ->
|
||||
// iterate over nodes in this root
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = rootNode.getNodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
recursivelyUpdateRenderSectionNode(playerPos, rootNode, quadNode, sectionPos);
|
||||
});
|
||||
});
|
||||
QuadNode<LodRenderSection> quadNode = nodeIterator.next();
|
||||
recursivelyUpdateRenderSectionNode(playerPos, rootNode, quadNode, quadNode.sectionPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void recursivelyUpdateRenderSectionNode(DhBlockPos2D playerPos, QuadNode<LodRenderSection> rootNode, QuadNode<LodRenderSection> nullableQuadNode, DhSectionPos sectionPos)
|
||||
{
|
||||
@@ -215,10 +230,15 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
}
|
||||
else
|
||||
{
|
||||
nullableQuadNode.forEachDirectChildNode((childQuadNode, childSectionPosition) ->
|
||||
// TODO this never returns anything
|
||||
Iterator<DhSectionPos> childPosIterator = nullableQuadNode.getChildPosIterator();
|
||||
while (childPosIterator.hasNext())
|
||||
{
|
||||
recursivelyUpdateRenderSectionNode(playerPos, rootNode, childQuadNode, childSectionPosition);
|
||||
});
|
||||
DhSectionPos childPos = childPosIterator.next();
|
||||
QuadNode<LodRenderSection> childNode = rootNode.getNode(childPos);
|
||||
|
||||
recursivelyUpdateRenderSectionNode(playerPos, rootNode, childNode, childPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO this should only equal the expected detail level, the (expectedDetailLevel-1) is a temporary fix to prevent corners from being cut out
|
||||
@@ -336,28 +356,16 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
{
|
||||
LOGGER.info("Clearing render cache...");
|
||||
|
||||
this.forEachRootNode((rootNode) ->
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
rootNode.forEachDirectChildNode((quadNode, sectionPos) ->
|
||||
QuadNode<LodRenderSection> quadNode = nodeIterator.next();
|
||||
if (quadNode.value != null)
|
||||
{
|
||||
if (quadNode != null && quadNode.value != null)
|
||||
{
|
||||
quadNode.value.disposeRenderData();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.forEachRootNode((rootNode) ->
|
||||
{
|
||||
rootNode.forEachDirectChildNode((quadNode, sectionPos) ->
|
||||
{
|
||||
if (quadNode != null && quadNode.value != null)
|
||||
{
|
||||
quadNode.value.disposeRenderData();
|
||||
quadNode.value = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
quadNode.value.disposeRenderData();
|
||||
quadNode.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the cache files
|
||||
this.renderSourceProvider.deleteRenderCache();
|
||||
@@ -402,16 +410,16 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
{
|
||||
LOGGER.info("Shutting down "+ LodQuadTree.class.getSimpleName()+"...");
|
||||
|
||||
this.forEachRootNode((rootNode) ->
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
rootNode.forEachDirectChildNode((quadNode, sectionPos) ->
|
||||
QuadNode<LodRenderSection> quadNode = nodeIterator.next();
|
||||
if (quadNode.value != null)
|
||||
{
|
||||
if (quadNode != null && quadNode.value != null)
|
||||
{
|
||||
quadNode.value.disposeRenderData();
|
||||
}
|
||||
});
|
||||
});
|
||||
quadNode.value.disposeRenderData();
|
||||
quadNode.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.info("Finished shutting down "+ LodQuadTree.class.getSimpleName());
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@ import com.seibel.lod.core.render.renderer.LodRenderer;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.math.Vec3f;
|
||||
import com.seibel.lod.core.util.objects.SortedArraySet;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadNode;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This object tells the {@link LodRenderer} what buffers to render
|
||||
@@ -135,8 +137,15 @@ public class RenderBufferHandler
|
||||
|
||||
// Build the sorted list
|
||||
this.loadedNearToFarBuffers = new SortedArraySet<>((a, b) -> -farToNearComparator.compare(a, b)); // TODO is the comparator named wrong?
|
||||
this.quadTree.forEachValue((renderSection, sectionPos) ->
|
||||
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.quadTree.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
QuadNode<LodRenderSection> node = nodeIterator.next();
|
||||
|
||||
DhSectionPos sectionPos = node.sectionPos;
|
||||
LodRenderSection renderSection = node.value;
|
||||
|
||||
if (renderSection != null && renderSection.shouldRender())
|
||||
{
|
||||
if (renderSection.renderBufferRef.get() != null && renderSection.renderBufferRef.get().areBuffersUploaded())
|
||||
@@ -144,7 +153,7 @@ public class RenderBufferHandler
|
||||
this.loadedNearToFarBuffers.add(new LoadedRenderBuffer(renderSection.renderBufferRef.get(), sectionPos));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void renderOpaque(LodRenderer renderContext)
|
||||
@@ -160,8 +169,10 @@ public class RenderBufferHandler
|
||||
|
||||
public void update()
|
||||
{
|
||||
this.quadTree.forEachValue((renderSection, sectionPos) ->
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.quadTree.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
LodRenderSection renderSection = nodeIterator.next().value;
|
||||
if (renderSection != null)
|
||||
{
|
||||
ColumnRenderSource currentRenderSource = renderSection.getRenderSource();
|
||||
@@ -182,19 +193,21 @@ public class RenderBufferHandler
|
||||
currentRenderSource.trySwapInNewlyBuiltRenderBuffer(renderSection.getRenderSource(), renderSection.renderBufferRef);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
this.quadTree.forEachValue((renderSection) ->
|
||||
{
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.quadTree.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
LodRenderSection renderSection = nodeIterator.next().value;
|
||||
if (renderSection != null && renderSection.renderBufferRef.get() != null)
|
||||
{
|
||||
renderSection.renderBufferRef.get().close();
|
||||
renderSection.renderBufferRef.set(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user