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/render/LodQuadTree.java b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java index 2451ac64d..a783c8620 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 @@ -15,6 +15,7 @@ import org.apache.logging.log4j.Logger; import java.util.HashSet; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; /** * This quadTree structure is our core data structure and holds @@ -31,9 +32,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! @@ -76,7 +77,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); } @@ -88,12 +89,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 @@ -106,12 +106,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()) @@ -348,7 +347,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..b87b9f369 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 @@ -8,6 +8,7 @@ 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.DhSectionPos; +import com.seibel.lod.core.render.LodRenderSection; 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; @@ -22,11 +23,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 +74,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,21 +127,18 @@ 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; @@ -131,6 +150,13 @@ public class DebugRenderer { renderBox(blockMin.x, minY, blockMin.z, blockMax.x, maxY, blockMax.z, color); } + public void renderBox(DhSectionPos sectPos, float minY, float maxY, float marginPercent, Color color) { + DhBlockPos2D blockMin = sectPos.getCorner().getCornerBlockPos(); + DhBlockPos2D blockMax = blockMin.add(sectPos.getWidth().toBlockWidth(), sectPos.getWidth().toBlockWidth()); + float edge = sectPos.getWidth().toBlockWidth() * marginPercent; + renderBox(blockMin.x + edge, minY, blockMin.z + edge, blockMax.x - edge, maxY, blockMax.z - edge, color); + } + public void renderBox(float x, float y, float z, float x2, float y2, float z2, Color color) { Vec3f boxPos = new Vec3f(x - camf.x, y - camf.y, z - camf.z); Mat4f boxTransform = Mat4f.createTranslateMatrix(boxPos.x, boxPos.y, boxPos.z); @@ -165,9 +191,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); +}