diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java index c706a9dc2..6d244bb07 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java @@ -65,6 +65,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo public final int dataPointsPerSection; public boolean isEmpty = true; public EDhApiWorldGenerationStep worldGenStep = EDhApiWorldGenerationStep.EMPTY; + private boolean isPromoted = false; @@ -614,10 +615,15 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo return this; } } - + isPromoted = true; CompleteFullDataSource fullDataSource = CompleteFullDataSource.createEmpty(this.sectionPos); this.applyToFullDataSource(fullDataSource); return fullDataSource; } - + + @Override + public boolean hasBeenPromoted() { + return isPromoted; + } + } diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java index 832ab2866..9758951c6 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java @@ -52,6 +52,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp private boolean isEmpty = true; public EDhApiWorldGenerationStep worldGenStep = EDhApiWorldGenerationStep.EMPTY; + private boolean isPromoted = false; @@ -514,12 +515,16 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp { return this; } - + isPromoted = true; return new CompleteFullDataSource(this.sectionPos, this.mapping, this.dataArrays); } - - - + + @Override + public boolean hasBeenPromoted() { + return isPromoted; + } + + //================// // helper classes // //================// diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IIncompleteFullDataSource.java b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IIncompleteFullDataSource.java index 074302530..427236c42 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IIncompleteFullDataSource.java @@ -17,5 +17,6 @@ public interface IIncompleteFullDataSource extends IFullDataSource * @return a new {@link CompleteFullDataSource} if successful, this if the promotion failed, . */ IFullDataSource tryPromotingToCompleteDataSource(); - + + boolean hasBeenPromoted(); } diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java b/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java index 0c7b5c8d3..a89634dd1 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java @@ -3,6 +3,7 @@ package com.seibel.lod.core.dataObjects.render.bufferBuilding; import com.seibel.lod.core.pos.DhBlockPos2D; import com.seibel.lod.core.pos.DhSectionPos; import com.seibel.lod.core.render.renderer.DebugRenderer; +import com.seibel.lod.core.render.renderer.IDebugRenderable; import com.seibel.lod.core.render.renderer.LodRenderer; import com.seibel.lod.core.render.AbstractRenderBuffer; import com.seibel.lod.core.config.Config; @@ -27,7 +28,7 @@ import static com.seibel.lod.core.render.glObject.GLProxy.GL_LOGGER; * * @see ColumnRenderBufferBuilder */ -public class ColumnRenderBuffer extends AbstractRenderBuffer +public class ColumnRenderBuffer extends AbstractRenderBuffer implements IDebugRenderable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -55,14 +56,16 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer this.debugPos = debugPos; vbos = new GLVertexBuffer[0]; vbosTransparent = new GLVertexBuffer[0]; - DebugRenderer.register(this, (r) -> { - if (closed || this.vbos == null) { - return; - } + DebugRenderer.register(this); + } - Color c = Color.green; - r.renderBox(debugPos, -32, 32, c); - }); + public void debugRender(DebugRenderer r) + { + if (closed || vbos == null) { + return; + } + Color c = Color.green; + r.renderBox(debugPos, 128, 128, 0.05f, c); } diff --git a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java index 2e4253df0..2c62fcb4a 100644 --- a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java @@ -178,7 +178,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider while (--sectionDetail >= this.minDetailLevel) { DhLodPos minPos = pos.getCorner().getCornerLodPos(sectionDetail); - int count = pos.getSectionBBoxPos().getBlockWidth(sectionDetail); + int count = pos.getSectionBBoxPos().getWidthAtDetail(sectionDetail); for (int xOffset = 0; xOffset < count; xOffset++) { diff --git a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java index c801e313c..3a67b2e16 100644 --- a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -1,10 +1,12 @@ package com.seibel.lod.core.file.fullDatafile; import com.seibel.lod.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor; +import com.seibel.lod.core.dataObjects.fullData.sources.CompleteFullDataSource; import com.seibel.lod.core.dataObjects.fullData.sources.HighDetailIncompleteFullDataSource; import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; import com.seibel.lod.core.dataObjects.fullData.sources.LowDetailIncompleteFullDataSource; +import com.seibel.lod.core.file.metaData.BaseMetaData; import com.seibel.lod.core.generation.tasks.IWorldGenTaskTracker; import com.seibel.lod.core.generation.WorldGenerationQueue; import com.seibel.lod.core.generation.tasks.WorldGenResult; @@ -21,6 +23,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Function; public class GeneratedFullDataFileHandler extends FullDataFileHandler { @@ -173,7 +176,17 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler .thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource()); } } - + +/* @Override + public CompletableFuture onDataFileRefresh(IFullDataSource source, BaseMetaData metaData, Function updater, Consumer onUpdated) + { + return super.onDataFileRefresh(source, metaData, updater, (IFullDataSource d) -> { + if (d instanceof CompleteFullDataSource) { + + } + } + }*/ + /** * Checks if the given {@link IFullDataSource} is fully generated and * if it isn't, creates the necessary world gen request(s) to finish it.
@@ -351,7 +364,10 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler @Override - public boolean isMemoryAddressValid() { return this.targetFullDataSourceRef.get() != null; } + public boolean isMemoryAddressValid() { + IFullDataSource ref = this.targetFullDataSourceRef.get(); + return ref != null && !((IIncompleteFullDataSource)ref).hasBeenPromoted(); + } @Override public Consumer getOnGenTaskCompleteConsumer() diff --git a/core/src/main/java/com/seibel/lod/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/lod/core/generation/WorldGenerationQueue.java index 6eb15d9e7..3421b83ea 100644 --- a/core/src/main/java/com/seibel/lod/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/lod/core/generation/WorldGenerationQueue.java @@ -10,6 +10,8 @@ import com.seibel.lod.core.dependencyInjection.SingletonInjector; import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler; import com.seibel.lod.core.generation.tasks.*; import com.seibel.lod.core.pos.*; +import com.seibel.lod.core.render.renderer.DebugRenderer; +import com.seibel.lod.core.render.renderer.IDebugRenderable; 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; @@ -20,12 +22,13 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import org.apache.logging.log4j.Logger; +import java.awt.*; import java.io.Closeable; import java.util.*; import java.util.concurrent.*; import java.util.function.Consumer; -public class WorldGenerationQueue implements Closeable +public class WorldGenerationQueue implements Closeable, IDebugRenderable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -95,6 +98,7 @@ public class WorldGenerationQueue implements Closeable { throw new IllegalArgumentException(IDhApiWorldGenerator.class.getSimpleName() + ": max granularity smaller than min granularity!"); } + DebugRenderer.register(this); } @@ -242,7 +246,9 @@ public class WorldGenerationQueue implements Closeable // } // } // } - + + private final Set CheckingTasks = Collections.newSetFromMap(new ConcurrentHashMap<>()); + /** * @param targetPos the position to center the generation around * @return false if no tasks were found to generate @@ -252,6 +258,7 @@ public class WorldGenerationQueue implements Closeable long closestGenDist = Long.MAX_VALUE; WorldGenTask closestTask = null; + CheckingTasks.clear(); // TODO improve, having to go over every node isn't super efficient, removing null nodes from the tree would help Iterator> nodeIterator = this.waitingTaskQuadTree.nodeIterator(); @@ -263,10 +270,11 @@ public class WorldGenerationQueue implements Closeable if (newGenTask != null) // TODO add an option to skip leaves with null values and potentially auto-prune them { + CheckingTasks.add(newGenTask); // TODO this isn't a long term fix, in the long term the tree should automatically remove out of bound nodes when moved - if (!this.waitingTaskQuadTree.isSectionPosInBounds(taskSectionPos)) + if (!this.waitingTaskQuadTree.isSectionPosInBounds(taskSectionPos) || !newGenTask.StillValid()) { - // skip and remove out-of-bound tasks + // skip and remove out-of-bound tasks or tasks that are no longer valid taskNode.value = null; continue; } @@ -289,14 +297,10 @@ public class WorldGenerationQueue implements Closeable return false; } - - // remove the task we found, we are going to start it and don't want to run it multiple times // TODO the setValue can fail if the user is moving and the task that was once in range is no longer in range WorldGenTask removedWorldGenTask = this.waitingTaskQuadTree.setValue(new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z), null); - - // do we need to modify this task to generate it? if(this.canGeneratePos((byte) 0, closestTask.pos)) // TODO should detail level 0 be replaced? { @@ -371,7 +375,6 @@ public class WorldGenerationQueue implements Closeable DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getCornerBlockPos()); - // check if this is a duplicate generation task if (this.alreadyGeneratedPosHashSet.contains(inProgressTaskGroup.group.pos)) { @@ -578,6 +581,8 @@ public class WorldGenerationQueue implements Closeable LOGGER.info("Finished closing "+WorldGenerationQueue.class.getSimpleName()); + + DebugRenderer.unregister(this); } @@ -616,6 +621,16 @@ public class WorldGenerationQueue implements Closeable return index; } - - + + + @Override + public void debugRender(DebugRenderer r) { + CheckingTasks.forEach((t) -> { + DhLodPos pos = t.pos; + r.renderBox(pos, -32f, 64f, 0.05f, Color.blue); + }); + this.inProgressGenTasksByLodPos.forEach((pos, t) -> { + r.renderBox(pos, -30f, 64f, 0.05f, Color.red); + }); + } } diff --git a/core/src/main/java/com/seibel/lod/core/generation/tasks/WorldGenTask.java b/core/src/main/java/com/seibel/lod/core/generation/tasks/WorldGenTask.java index 812aab9b5..4e33f5b90 100644 --- a/core/src/main/java/com/seibel/lod/core/generation/tasks/WorldGenTask.java +++ b/core/src/main/java/com/seibel/lod/core/generation/tasks/WorldGenTask.java @@ -25,5 +25,8 @@ public final class WorldGenTask this.taskTracker = taskTracker; this.future = future; } - + + public boolean StillValid() { + return taskTracker.isMemoryAddressValid(); + } } diff --git a/core/src/main/java/com/seibel/lod/core/pos/DhLodPos.java b/core/src/main/java/com/seibel/lod/core/pos/DhLodPos.java index 0b591d6ad..83e8e3ea4 100644 --- a/core/src/main/java/com/seibel/lod/core/pos/DhLodPos.java +++ b/core/src/main/java/com/seibel/lod/core/pos/DhLodPos.java @@ -39,19 +39,22 @@ public class DhLodPos implements Comparable public DhLodUnit getX() { return new DhLodUnit(this.detailLevel, this.x); } public DhLodUnit getZ() { return new DhLodUnit(this.detailLevel, this.z); } - - public int getBlockWidth() { return this.getBlockWidth(this.detailLevel); } - public int getBlockWidth(byte detailLevel) // TODO this needs some documentation or a better name describing what is happening, why is there an assert here? + + // Get the width of this pos, measured in the mc block unit. (i.e. detail 0) + public int getBlockWidth() { return this.getWidthAtDetail((byte)0); } + + // Get the width of this pos, measured in the target detail level. + public int getWidthAtDetail(byte targetLevel) { - LodUtil.assertTrue(detailLevel <= this.detailLevel); - return BitShiftUtil.powerOfTwo(this.detailLevel - detailLevel); + LodUtil.assertTrue(targetLevel <= this.detailLevel); + return BitShiftUtil.powerOfTwo(this.detailLevel - targetLevel); } public DhBlockPos2D getCenterBlockPos() { return new DhBlockPos2D( this.getX().toBlockWidth() + BitShiftUtil.half(this.getBlockWidth()), - this.getZ().toBlockWidth() + BitShiftUtil.half(this.getBlockWidth())); + this.getZ().toBlockWidth() + BitShiftUtil.half(this.getBlockWidth())); } public DhBlockPos2D getCornerBlockPos() { return new DhBlockPos2D(this.getX().toBlockWidth(), this.getZ().toBlockWidth()); } diff --git a/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java index 22f5a76c8..a3e813222 100644 --- a/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java @@ -16,6 +16,7 @@ import org.apache.logging.log4j.Logger; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; /** * This quadTree structure is our core data structure and holds @@ -32,9 +33,9 @@ public class LodQuadTree extends QuadTree implements AutoClose /** * This holds every {@link DhSectionPos} that should be reloaded next tick.
- * This is a {@link ConcurrentHashMap} because new sections can be added to this list via the world generator threads. + * This is a {@link ConcurrentLinkedQueue} because new sections can be added to this list via the world generator threads. */ - private final ConcurrentHashMap sectionsToReload = new ConcurrentHashMap<>(); + private final ConcurrentLinkedQueue sectionsToReload = new ConcurrentLinkedQueue<>(); private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference! @@ -80,7 +81,7 @@ public class LodQuadTree extends QuadTree implements AutoClose try { // recenter if necessary, removing out of bounds sections - this.setCenterBlockPos(playerPos, LodRenderSection::disposeRenderData); + this.setCenterBlockPos(playerPos, LodRenderSection::dispose); updateAllRenderSections(playerPos); } @@ -92,12 +93,11 @@ public class LodQuadTree extends QuadTree implements AutoClose private void updateAllRenderSections(DhBlockPos2D playerPos) { // reload any sections that need it - DhSectionPos[] reloadSectionArray = this.sectionsToReload.keySet().toArray(new DhSectionPos[0]); - this.sectionsToReload.clear(); - for (DhSectionPos pos : reloadSectionArray) + DhSectionPos pos; + while ((pos = this.sectionsToReload.poll()) != null) { // walk up the tree until we hit the root node - // this is done so any high detail changes flow up to the lower detail render sections as well + // this is done so any high detail changes flow up to the lower detail render sections as well while (pos.sectionDetailLevel <= this.treeMaxDetailLevel) { try @@ -110,12 +110,11 @@ public class LodQuadTree extends QuadTree implements AutoClose } catch (IndexOutOfBoundsException e) { /* the section is now out of bounds, it doesn't need to be reloaded */ } - + pos = pos.getParentPos(); } } - - + // walk through each root node Iterator rootPosIterator = this.rootNodePosIterator(); while (rootPosIterator.hasNext()) @@ -352,7 +351,7 @@ public class LodQuadTree extends QuadTree implements AutoClose } //LOGGER.info("LodQuadTree reloadPos ["+pos+"]."); - this.sectionsToReload.put(pos, true); + this.sectionsToReload.add(pos); } diff --git a/core/src/main/java/com/seibel/lod/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/lod/core/render/LodRenderSection.java index eca316c7d..227b0f3e9 100644 --- a/core/src/main/java/com/seibel/lod/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/lod/core/render/LodRenderSection.java @@ -6,8 +6,12 @@ import com.seibel.lod.core.level.IDhClientLevel; import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.pos.DhSectionPos; import com.seibel.lod.core.file.renderfile.ILodRenderSourceProvider; +import com.seibel.lod.core.render.renderer.DebugRenderer; +import com.seibel.lod.core.render.renderer.IDebugRenderable; import org.apache.logging.log4j.Logger; +import java.awt.*; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -15,7 +19,7 @@ import java.util.concurrent.atomic.AtomicReference; * A render section represents an area that could be rendered. * For more information see {@link LodQuadTree}. */ -public class LodRenderSection +public class LodRenderSection implements IDebugRenderable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -38,7 +42,30 @@ public class LodRenderSection - public LodRenderSection(DhSectionPos pos) { this.pos = pos; } + public LodRenderSection(DhSectionPos pos) { + this.pos = pos; + + DebugRenderer.register(this); + } + + public void debugRender(DebugRenderer r) + { + Color color = Color.red; + + if (this.renderSourceProvider == null) color = Color.black; + + if (this.renderSourceLoadFuture != null) color = Color.yellow; + + if (renderSource != null) { + color = Color.blue; + if (isRenderingEnabled) color = Color.cyan; + if (isRenderingEnabled && isRenderDataLoaded()) color = Color.green; + } + + float yOffset = Objects.hashCode(this) / (float) Integer.MAX_VALUE * 16f; + + r.renderBox(this.pos, yOffset, yOffset, 0.1f, color); + } @@ -160,6 +187,8 @@ public class LodRenderSection this.renderSourceLoadFuture.cancel(true); this.renderSourceLoadFuture = null; } + + this.renderSourceProvider = null; } @@ -208,5 +237,9 @@ public class LodRenderSection ", isRenderEnabled=" + this.isRenderingEnabled + '}'; } - + + public void dispose() { + DebugRenderer.unregister(this); + disposeRenderData(); + } } diff --git a/core/src/main/java/com/seibel/lod/core/render/renderer/DebugRenderer.java b/core/src/main/java/com/seibel/lod/core/render/renderer/DebugRenderer.java index 370619796..b8ebf1c3e 100644 --- a/core/src/main/java/com/seibel/lod/core/render/renderer/DebugRenderer.java +++ b/core/src/main/java/com/seibel/lod/core/render/renderer/DebugRenderer.java @@ -7,8 +7,8 @@ import com.seibel.lod.core.dependencyInjection.SingletonInjector; import com.seibel.lod.core.logging.ConfigBasedLogger; import com.seibel.lod.core.logging.ConfigBasedSpamLogger; import com.seibel.lod.core.pos.DhBlockPos2D; +import com.seibel.lod.core.pos.DhLodPos; import com.seibel.lod.core.pos.DhSectionPos; -import com.seibel.lod.core.render.glObject.GLProxy; import com.seibel.lod.core.render.glObject.GLState; import com.seibel.lod.core.render.glObject.buffer.GLElementBuffer; import com.seibel.lod.core.render.glObject.buffer.GLVertexBuffer; @@ -22,11 +22,10 @@ import org.apache.logging.log4j.LogManager; import org.lwjgl.opengl.GL32; import java.awt.*; +import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; +import java.util.*; public class DebugRenderer { public static DebugRenderer INSTANCE = new DebugRenderer(); @@ -74,12 +73,34 @@ public class DebugRenderer { VertexAttribute va; boolean init = false; + public static void unregister(IDebugRenderable r) { + if (INSTANCE == null) return; + INSTANCE.removeRenderer(r); + } + + private void removeRenderer(IDebugRenderable r) { + synchronized (renderers) { + Iterator> it = renderers.iterator(); + while (it.hasNext()) { + WeakReference ref = it.next(); + if (ref.get() == null) { + it.remove(); + continue; + } + if (ref.get() == r) { + it.remove(); + return; + } + } + } + } + public void init() { if (init) return; init = true; va = VertexAttribute.create(); va.bind(); - // Pos + // Pos\ va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec3Pointer(false)); va.completeAndCheck(Float.BYTES * 3); basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag", @@ -105,30 +126,40 @@ public class DebugRenderer { boxOutlineBuffer.uploadBuffer(buffer, EGpuUploadMethod.DATA, box_outline_indices.length * Integer.BYTES, GL32.GL_STATIC_DRAW); } - @FunctionalInterface - public interface IDebugRender { - void render(DebugRenderer r); - } + private final LinkedList> renderers = new LinkedList<>(); - private final Map renderers = Collections.synchronizedMap(new WeakHashMap<>()); - - public void addRenderer(Object o, IDebugRender r) { + public void addRenderer(IDebugRenderable r) { if (!Config.Client.Advanced.Debugging.debugWireframeRendering.get()) return; - renderers.put(o, r); + synchronized (renderers) { + renderers.add(new WeakReference<>(r)); + } } - public static void register(Object o, IDebugRender r) { + public static void register(IDebugRenderable r) { if (INSTANCE == null) return; - INSTANCE.addRenderer(o, r); + INSTANCE.addRenderer(r); } private Mat4f transform_this_frame; private Vec3f camf; + public void renderBox(DhLodPos pos, float minY, float maxY, float marginPercent, Color color) { + DhBlockPos2D blockMin = pos.getCornerBlockPos(); + DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth()); + float edge = pos.getBlockWidth() * marginPercent; + renderBox(blockMin.x + edge, minY, blockMin.z + edge, blockMax.x - edge, maxY, blockMax.z - edge, color); + } + + public void renderBox(DhLodPos pos, float minY, float maxY, Color color) { + renderBox(pos, minY, maxY, 0, color); + } + public void renderBox(DhSectionPos sectPos, float minY, float maxY, Color color) { - DhBlockPos2D blockMin = sectPos.getCorner().getCornerBlockPos(); - DhBlockPos2D blockMax = blockMin.add(sectPos.getWidth().toBlockWidth(), sectPos.getWidth().toBlockWidth()); - renderBox(blockMin.x, minY, blockMin.z, blockMax.x, maxY, blockMax.z, color); + renderBox(sectPos.getSectionBBoxPos(), minY, maxY, 0, color); + } + + public void renderBox(DhSectionPos sectPos, float minY, float maxY, float marginPercent, Color color) { + renderBox(sectPos.getSectionBBoxPos(), minY, maxY, marginPercent, color); } public void renderBox(float x, float y, float z, float x2, float y2, float z2, Color color) { @@ -165,9 +196,22 @@ public class DebugRenderer { basicShader.bind(); va.bind(); va.bindBufferToAllBindingPoint(boxBuffer.getId()); + boxOutlineBuffer.bind(); - renderers.forEach((o, r) -> r.render(this)); + synchronized (renderers) + { + Iterator> it = renderers.iterator(); + while (it.hasNext()) { + WeakReference ref = it.next(); + IDebugRenderable r = ref.get(); + if (r == null) { + it.remove(); + continue; + } + r.debugRender(this); + } + } state.restore(); } diff --git a/core/src/main/java/com/seibel/lod/core/render/renderer/IDebugRenderable.java b/core/src/main/java/com/seibel/lod/core/render/renderer/IDebugRenderable.java new file mode 100644 index 000000000..30a38f8bd --- /dev/null +++ b/core/src/main/java/com/seibel/lod/core/render/renderer/IDebugRenderable.java @@ -0,0 +1,5 @@ +package com.seibel.lod.core.render.renderer; + +public interface IDebugRenderable { + void debugRender(DebugRenderer r); +}