From 082f7597b28dfb5e1863627e523dc4e889b3577b Mon Sep 17 00:00:00 2001 From: TomTheFurry Date: Mon, 12 Jun 2023 13:25:37 +0800 Subject: [PATCH] FIx misc bugs and issues, and polish, simplify and remove no-longer needed logic --- .../bufferBuilding/ColumnRenderBuffer.java | 2 +- .../fullDatafile/FullDataFileHandler.java | 24 +-- .../file/fullDatafile/FullDataMetaFile.java | 4 +- .../GeneratedFullDataFileHandler.java | 137 +++++++++++++++++- .../fullDatafile/IFullDataSourceProvider.java | 2 +- .../core/generation/WorldGenerationQueue.java | 29 ++-- .../com/seibel/lod/core/pos/DhSectionPos.java | 14 ++ .../lod/core/render/LodRenderSection.java | 2 +- .../core/render/renderer/DebugRenderer.java | 2 +- .../lod/core/render/renderer/LodRenderer.java | 2 +- 10 files changed, 179 insertions(+), 39 deletions(-) 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 a89634dd1..3eed6c13c 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 @@ -65,7 +65,7 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer implements IDebugRe return; } Color c = Color.green; - r.renderBox(debugPos, 128, 128, 0.05f, c); + //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 2c62fcb4a..ddd3acad5 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 @@ -168,28 +168,28 @@ public class FullDataFileHandler implements IFullDataSourceProvider * @param preexistingFiles the list of {@link FullDataMetaFile}'s that have been created for the given position. * @param missingFilePositions the list of {@link DhSectionPos}'s that don't have {@link FullDataMetaFile} created for them yet. */ - protected void getDataFilesForPosition(DhSectionPos basePos, DhSectionPos pos, + protected void getDataFilesForPosition(DhSectionPos effectivePos, DhSectionPos posAreaToGet, ArrayList preexistingFiles, ArrayList missingFilePositions) { - byte sectionDetail = pos.sectionDetailLevel; + byte sectionDetail = posAreaToGet.sectionDetailLevel; boolean allEmpty = true; outerLoop: while (--sectionDetail >= this.minDetailLevel) { - DhLodPos minPos = pos.getCorner().getCornerLodPos(sectionDetail); - int count = pos.getSectionBBoxPos().getWidthAtDetail(sectionDetail); + DhLodPos minPos = posAreaToGet.getCorner().getCornerLodPos(sectionDetail); + int count = posAreaToGet.getSectionBBoxPos().getWidthAtDetail(sectionDetail); for (int xOffset = 0; xOffset < count; xOffset++) { for (int zOffset = 0; zOffset < count; zOffset++) { DhSectionPos subPos = new DhSectionPos(sectionDetail, xOffset+minPos.x, zOffset+minPos.z); - LodUtil.assertTrue(pos.overlaps(basePos) && subPos.overlaps(pos)); + LodUtil.assertTrue(posAreaToGet.overlaps(effectivePos) && subPos.overlaps(posAreaToGet)); //TODO: The following check is temporary as we only sample corner points, which means // on a very different level, we may not need the entire section at all. - if (!CompleteFullDataSource.firstDataPosCanAffectSecond(basePos, subPos)) + if (!CompleteFullDataSource.firstDataPosCanAffectSecond(effectivePos, subPos)) { continue; } @@ -207,15 +207,15 @@ public class FullDataFileHandler implements IFullDataSourceProvider { // there are no children to this quad tree, // add this leaf's position - missingFilePositions.add(pos); + missingFilePositions.add(posAreaToGet); } else { // there are children in this quad tree, search them - this.recursiveGetDataFilesForPosition(0, basePos, pos, preexistingFiles, missingFilePositions); - this.recursiveGetDataFilesForPosition(1, basePos, pos, preexistingFiles, missingFilePositions); - this.recursiveGetDataFilesForPosition(2, basePos, pos, preexistingFiles, missingFilePositions); - this.recursiveGetDataFilesForPosition(3, basePos, pos, preexistingFiles, missingFilePositions); + this.recursiveGetDataFilesForPosition(0, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions); + this.recursiveGetDataFilesForPosition(1, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions); + this.recursiveGetDataFilesForPosition(2, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions); + this.recursiveGetDataFilesForPosition(3, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions); } } private void recursiveGetDataFilesForPosition(int childIndex, DhSectionPos basePos, DhSectionPos pos, ArrayList preexistingFiles, ArrayList missingFilePositions) @@ -403,7 +403,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider @Override public IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData, - Consumer onUpdated, Function updater) + Consumer onUpdated, Function updater, boolean justCreated) { boolean changed = updater.apply(source); // if (changed) diff --git a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataMetaFile.java index e1cb72d09..0e507c1dd 100644 --- a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataMetaFile.java @@ -163,7 +163,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile this.baseMetaData = this._makeBaseMetaData(fullDataSource); return fullDataSource; }) - .thenApply((fullDataSource) -> this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource)) + .thenApply((fullDataSource) -> this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource, true)) .whenComplete((fullDataSource, exception) -> { if (exception != null) @@ -225,7 +225,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile "loading one into the cache! Is this a deadlock?"); // fire the onDataLoaded method - fullDataSource = this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource); + fullDataSource = this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource, false); return fullDataSource; }, executorService) 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 3a67b2e16..7a3688c9c 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 @@ -17,6 +17,7 @@ import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.util.LodUtil; import org.apache.logging.log4j.Logger; +import javax.annotation.Nullable; import java.io.File; import java.lang.ref.WeakReference; import java.util.*; @@ -24,6 +25,8 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class GeneratedFullDataFileHandler extends FullDataFileHandler { @@ -52,7 +55,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { return super.read(pos).whenComplete((fullDataSource, ex) -> { - this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource); + //this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource); }); } @@ -86,11 +89,125 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler //========// // events // //========// + + private CompletableFuture spawnGenTasks(FullDataMetaFile file, @Nullable IIncompleteFullDataSource data) + { + DhSectionPos pos = file.pos; + + ArrayList existingFiles = new ArrayList<>(); + ArrayList missingPositions = new ArrayList<>(); + this.getDataFilesForPosition(pos, pos, existingFiles, missingPositions); + + // confirm the quad tree has at least one node in it + LodUtil.assertTrue(!missingPositions.isEmpty() || !existingFiles.isEmpty()); + + + + // determine the type of dataSource that should be used for this position + IIncompleteFullDataSource incompleteFullDataSource; + if (data == null) + { + if (pos.sectionDetailLevel <= HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL) + { + incompleteFullDataSource = HighDetailIncompleteFullDataSource.createEmpty(pos); + } + else + { + incompleteFullDataSource = LowDetailIncompleteFullDataSource.createEmpty(pos); + } + } + else + { + incompleteFullDataSource = data; + } + + // breaks down the missing positions into the desired detail level that the gen queue could accept + byte maxSectDataDetailLevel = worldGenQueueRef.get().largestDataDetail; + byte targetDataDetailLevel = incompleteFullDataSource.getDataDetailLevel(); + if (targetDataDetailLevel > maxSectDataDetailLevel) { + byte sectDetailLevel = (byte) (DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL + maxSectDataDetailLevel); + missingPositions = missingPositions.stream() + .flatMap(missingPos -> { + if (missingPos.sectionDetailLevel > sectDetailLevel) { + // split this position into smaller positions + ArrayList splitPositions = new ArrayList<>(); + missingPos.forEachChildAtLevel(sectDetailLevel, splitPositions::add); + return splitPositions.stream(); + } + else { + return Stream.of(missingPos); + } + }) + .collect(Collectors.toCollection(ArrayList::new)); + } + + if (missingPositions.size() == 1 && existingFiles.isEmpty() && missingPositions.get(0).equals(pos)) + { + // No LOD data exists for this position yet + + WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + if (worldGenQueue != null) + { + this.incompleteSourceGenRequests.add(pos); + + // queue this section to be generated + GenTask genTask = new GenTask(pos, new WeakReference<>(incompleteFullDataSource)); + worldGenQueue.submitGenTask(new DhLodPos(pos), incompleteFullDataSource.getDataDetailLevel(), genTask) + .whenComplete((genTaskResult, ex) -> + { + this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos); + this.fireOnGenPosSuccessListeners(pos); + this.incompleteSourceGenRequests.remove(pos); + }); + } + + // return the empty dataSource (it will be populated later) + return CompletableFuture.completedFuture(incompleteFullDataSource); + } + else + { + // LOD data exists for this position + + // create the missing metaData files + for (DhSectionPos missingPos : missingPositions) + { + FullDataMetaFile newFile = this.getOrMakeFile(missingPos); + if (newFile != null) + { + existingFiles.add(newFile); + } + } + + // LOGGER.debug("Creating "+pos+" from sampling "+existingFiles.size()+" files: "+existingFiles); + + // read in the existing data + final ArrayList> loadDataFutures = new ArrayList<>(existingFiles.size()); + for (FullDataMetaFile existingFile : existingFiles) + { + loadDataFutures.add(existingFile.loadOrGetCachedDataSourceAsync() + .exceptionally((ex) -> /*Ignore file read errors*/null) + .thenAccept((fullDataSource) -> + { + if (fullDataSource == null) + { + return; + } + //this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource); + //LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos); + incompleteFullDataSource.sampleFrom(fullDataSource); + }) + ); + } + return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0])) + .thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource()); + } + } @Override public CompletableFuture onCreateDataFile(FullDataMetaFile file) { - DhSectionPos pos = file.pos; + return this.spawnGenTasks(file, null); +/* DhSectionPos pos = file.pos; ArrayList existingFiles = new ArrayList<>(); ArrayList missingPositions = new ArrayList<>(); @@ -156,7 +273,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler for (FullDataMetaFile existingFile : existingFiles) { loadDataFutures.add(existingFile.loadOrGetCachedDataSourceAsync() - .exceptionally((ex) -> /*Ignore file read errors*/null) + .exceptionally((ex) -> *//*Ignore file read errors*//*null) .thenAccept((fullDataSource) -> { if (fullDataSource == null) @@ -174,7 +291,20 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0])) .thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource()); + }*/ + } + @Override + public IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData, + Consumer onUpdated, Function updater, boolean justCreated) + { + IFullDataSource fullDataSource = super.onDataFileLoaded(source, metaData, onUpdated, updater, justCreated); + if (fullDataSource instanceof CompleteFullDataSource || justCreated) { + return fullDataSource; } + + this.spawnGenTasks(getOrMakeFile(metaData.pos), (IIncompleteFullDataSource)fullDataSource); + //checkIfSectionNeedsAdditionalGeneration(metaData.pos, fullDataSource); + return fullDataSource; } /* @Override @@ -230,6 +360,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler // don't queue the same section twice if (this.incompleteSourceGenRequests.contains(ungenChildPos)) { + LOGGER.warn("checkIfSectionNeedsAdditionalGeneration skipping duplicate gen request for pos: ["+ungenChildPos+"]."); continue; } this.incompleteSourceGenRequests.add(ungenChildPos); diff --git a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/IFullDataSourceProvider.java b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/IFullDataSourceProvider.java index fee251382..8ac165f76 100644 --- a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/IFullDataSourceProvider.java +++ b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/IFullDataSourceProvider.java @@ -25,7 +25,7 @@ public interface IFullDataSourceProvider extends AutoCloseable //boolean isCacheVersionValid(DhSectionPos sectionPos, long cacheVersion); CompletableFuture onCreateDataFile(FullDataMetaFile file); - IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData, Consumer onUpdated, Function updater); + IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData, Consumer onUpdated, Function updater, boolean justCreated); CompletableFuture onDataFileRefresh(IFullDataSource source, BaseMetaData metaData, Function updater, Consumer onUpdated); File computeDataFilePath(DhSectionPos pos); ExecutorService getIOExecutor(); 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 3421b83ea..14588670a 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 @@ -44,7 +44,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable public final byte minGranularity; /** largest numerical detail level allowed */ - final byte largestDataDetail; + public final byte largestDataDetail; /** lowest numerical detail level allowed */ public final byte smallestDataDetail; @@ -65,7 +65,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable // debug variables to test for duplicate world generator requests // /** limits how many of the previous world gen requests we should track */ private static final int MAX_ALREADY_GENERATED_COUNT = 100; - private final HashSet alreadyGeneratedPosHashSet = new HashSet<>(MAX_ALREADY_GENERATED_COUNT); + private final HashMap alreadyGeneratedPosHashSet = new HashMap<>(MAX_ALREADY_GENERATED_COUNT); private final Queue alreadyGeneratedPosQueue = new LinkedList<>(); private static ExecutorService worldGeneratorThreadPool; @@ -271,8 +271,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable 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) || !newGenTask.StillValid()) + if (!newGenTask.StillValid()) { // skip and remove out-of-bound tasks or tasks that are no longer valid taskNode.value = null; @@ -298,7 +297,6 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable } // 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? @@ -322,6 +320,8 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable // Note: Due to concurrency reasons, even if the currently running task is compatible with // the newly selected task, we cannot use it, // as some chunks may have already been written into. + + LOGGER.warn("A task already exists for this position, todo: {}", closestTask.pos); } // a task has been started @@ -338,13 +338,6 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable DhSectionPos sectionPos = new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z); sectionPos.forEachChild((childDhSectionPos) -> { - if (!this.waitingTaskQuadTree.isSectionPosInBounds(childDhSectionPos)) - { - // don't attempt to generate terrain outside the user's render distance - return; - } - - CompletableFuture newFuture = new CompletableFuture<>(); childFutures.add(newFuture); @@ -376,16 +369,18 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getCornerBlockPos()); // check if this is a duplicate generation task - if (this.alreadyGeneratedPosHashSet.contains(inProgressTaskGroup.group.pos)) + if (this.alreadyGeneratedPosHashSet.containsKey(inProgressTaskGroup.group.pos)) { // temporary solution to prevent generating the same section multiple times LOGGER.warn("Duplicate generation section " + taskPos + " with granularity [" + granularity + "] at " + chunkPosMin + ". Skipping..."); - + + StackTraceElement[] stackTrace = this.alreadyGeneratedPosHashSet.get(inProgressTaskGroup.group.pos); + // sending a success result is necessary to make sure the render sections are reloaded correctly inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos)))); return; } - this.alreadyGeneratedPosHashSet.add(inProgressTaskGroup.group.pos); + this.alreadyGeneratedPosHashSet.put(inProgressTaskGroup.group.pos, Thread.currentThread().getStackTrace()); this.alreadyGeneratedPosQueue.add(inProgressTaskGroup.group.pos); // remove extra tracked duplicate positions @@ -627,10 +622,10 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable public void debugRender(DebugRenderer r) { CheckingTasks.forEach((t) -> { DhLodPos pos = t.pos; - r.renderBox(pos, -32f, 64f, 0.05f, Color.blue); + r.renderBox(pos, -32f, 128f, 0.05f, Color.blue); }); this.inProgressGenTasksByLodPos.forEach((pos, t) -> { - r.renderBox(pos, -30f, 64f, 0.05f, Color.red); + r.renderBox(pos, -30f, 128f, 0.05f, Color.red); }); } } diff --git a/core/src/main/java/com/seibel/lod/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/lod/core/pos/DhSectionPos.java index cff4424a4..b81f37b4e 100644 --- a/core/src/main/java/com/seibel/lod/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/lod/core/pos/DhSectionPos.java @@ -167,6 +167,20 @@ public class DhSectionPos callback.accept(this.getChildByIndex(i)); } } + + /** Applies the given consumer to all children of the position at the given section detail level. */ + public void forEachChildAtLevel(byte sectionDetailLevel, Consumer callback) + { + if (sectionDetailLevel == this.sectionDetailLevel) + { + callback.accept(this); + return; + } + for (int i = 0; i < 4; i++) + { + this.getChildByIndex(i).forEachChildAtLevel(sectionDetailLevel, callback); + } + } public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); } 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 227b0f3e9..6f8b108a2 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 @@ -64,7 +64,7 @@ public class LodRenderSection implements IDebugRenderable float yOffset = Objects.hashCode(this) / (float) Integer.MAX_VALUE * 16f; - r.renderBox(this.pos, yOffset, yOffset, 0.1f, color); + //r.renderBox(this.pos, yOffset, yOffset, 0.1f, color); } 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 b8ebf1c3e..bf8c32bb0 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 @@ -188,7 +188,7 @@ public class DebugRenderer { GL32.glViewport(0,0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight()); GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE); //GL32.glLineWidth(2); - GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glEnable(GL32.GL_DEPTH_TEST); GL32.glDisable(GL32.GL_STENCIL_TEST); GL32.glDisable(GL32.GL_BLEND); GL32.glDisable(GL32.GL_SCISSOR_TEST); diff --git a/core/src/main/java/com/seibel/lod/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/lod/core/render/renderer/LodRenderer.java index b0c9a8013..c4bd3abf3 100644 --- a/core/src/main/java/com/seibel/lod/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/lod/core/render/renderer/LodRenderer.java @@ -268,6 +268,7 @@ public class LodRenderer shaderProgram.unbind(); //lightmapTexture.free(); + DebugRenderer.INSTANCE.render(modelViewProjectionMatrix); GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT); currentState.restore(); @@ -277,7 +278,6 @@ public class LodRenderer profiler.pop(); tickLogger.incLogTries(); - DebugRenderer.INSTANCE.render(modelViewProjectionMatrix); }