diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java index 4e5fd3acc..eae828efc 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java @@ -112,19 +112,6 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup // advanced graphic settings // //===========================// - /** - * Sets whether LODs outside the view frustum culling will - * be culled.

- * - * Disabling this will prevent LODs not rendering on the corner - * of the users vision and may fix issues if LODs appear to - * start/stop rendering incorrectly based on the camera direction, - * but will also reduce FPS. - * - * @since API 1.1.0 - */ - IDhApiConfigValue disableFrustumCulling(); - /** * Sets the distance used by the near clip plane to reduce * overdraw.
@@ -187,4 +174,30 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup */ IDhApiConfigValue lodShading(); + /** + * Sets whether LODs outside the view frustum culling will + * be culled.

+ * + * Disabling this will prevent LODs not rendering on the corner + * of the users vision and may fix issues if LODs appear to + * start/stop rendering incorrectly based on the camera direction, + * but will also reduce FPS. + * + * @since API 1.1.0 + * @see IDhApiGraphicsConfig#disableShadowFrustumCulling() + */ + IDhApiConfigValue disableFrustumCulling(); + + /** + * Identical to the other frustum culling option, except that it is + * only used when a shader mod is present using the DH API + * and the shadow pass is being rendered.

+ * + * Disable this if shadows render incorrectly. + * + * @since API 1.1.0 + * @see IDhApiGraphicsConfig#disableFrustumCulling() + */ + IDhApiConfigValue disableShadowFrustumCulling(); + } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiShadowCullingFrustum.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiShadowCullingFrustum.java new file mode 100644 index 000000000..5759587a0 --- /dev/null +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiShadowCullingFrustum.java @@ -0,0 +1,43 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.api.interfaces.override.rendering; + +import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel; +import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; + +/** + * The culling frustum used during Distant Horizons' shadow pass + * if another mod has enabled Distant Horizons' shadow + * pass via the API.

+ * + * If no {@link IDhApiShadowCullingFrustum} is bound then culling + * will not be done in the shadow pass. + * + * @see IDhApiCullingFrustum + * + * @author James Seibel + * @version 2024-2-10 + * @since API 1.1.0 + */ +public interface IDhApiShadowCullingFrustum extends IDhApiCullingFrustum +{ + // should be identical to the parent culling frustum +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java index aded64723..63b810521 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java @@ -105,10 +105,6 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig // advanced graphic settings // //===========================// - @Override - public IDhApiConfigValue disableFrustumCulling() - { return new DhApiConfigValue(Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling); } - @Deprecated @Override public IDhApiConfigValue overdrawPrevention() @@ -150,6 +146,14 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig public IDhApiConfigValue lodShading() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading); } + @Override + public IDhApiConfigValue disableFrustumCulling() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling); } + + @Override + public IDhApiConfigValue disableShadowFrustumCulling() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.AdvancedGraphics.disableShadowPassFrustumCulling); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java index 002a2c630..acb3d418e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java @@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.f3.F3Screen; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.util.LodUtil; @@ -54,7 +55,7 @@ public class SharedApi private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - private static final Set UPDATING_CHUNK_SET = ConcurrentHashMap.newKeySet(); + private static final Set UPDATING_CHUNK_POS_SET = ConcurrentHashMap.newKeySet(); /** how many chunks can be queued for updating per thread, used to prevent updates from infinitely pilling up if the user flys around extremely fast */ private static final int MAX_UPDATING_CHUNK_COUNT_PER_THREAD = 500; private static final int MIN_MS_BETWEEN_OVERLOADED_LOG_MESSAGE = 5_000; @@ -79,7 +80,7 @@ public class SharedApi this.f3Message = new F3Screen.DynamicMessage(() -> { int maxUpdateCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get(); - return LodUtil.formatLog("Queued chunk updates: " + UPDATING_CHUNK_SET.size() + " / " + maxUpdateCount); + return LodUtil.formatLog("Queued chunk updates: " + UPDATING_CHUNK_POS_SET.size() + " / " + maxUpdateCount); }); } @@ -143,6 +144,13 @@ public class SharedApi // chunk update // //==============// + /** + * Used to prevent getting a full chunk from MC if it isn't necessary.
+ * This is important since asking MC for a chunk is slow and may block the render thread. + */ + public static boolean isChunkAtBlockPosAlreadyUpdating(int blockPosX, int blockPosZ) { return UPDATING_CHUNK_POS_SET.contains(new DhChunkPos(new DhBlockPos2D(blockPosX, blockPosZ))); } + + /** handles both block place and break events */ public void chunkBlockChangedEvent(IChunkWrapper chunk, ILevelWrapper level) { this.applyChunkUpdate(chunk, level, true); } @@ -206,7 +214,7 @@ public class SharedApi // task limiting check // //=====================// - int currentQueueCount = UPDATING_CHUNK_SET.size(); + int currentQueueCount = UPDATING_CHUNK_POS_SET.size(); int maxQueueCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get(); if (currentQueueCount >= maxQueueCount) { @@ -224,12 +232,12 @@ public class SharedApi } // prevent duplicate update requests - if (UPDATING_CHUNK_SET.contains(chunkWrapper.getChunkPos())) + if (UPDATING_CHUNK_POS_SET.contains(chunkWrapper.getChunkPos())) { // this chunk is already being updated return; } - UPDATING_CHUNK_SET.add(chunkWrapper.getChunkPos()); + UPDATING_CHUNK_POS_SET.add(chunkWrapper.getChunkPos()); @@ -343,13 +351,13 @@ public class SharedApi CHUNK_UPDATE_TIMER.schedule(new TimerTask() { @Override - public void run() { UPDATING_CHUNK_SET.remove(chunkWrapper.getChunkPos()); } + public void run() { UPDATING_CHUNK_POS_SET.remove(chunkWrapper.getChunkPos()); } }, updateTimeoutInSec * 1000L); } else { // instantly allow this chunk to be updated again - UPDATING_CHUNK_SET.remove(chunkWrapper.getChunkPos()); + UPDATING_CHUNK_POS_SET.remove(chunkWrapper.getChunkPos()); } } }); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index c524a1fae..6c5df861c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -30,6 +30,7 @@ import com.seibel.distanthorizons.core.config.types.*; import com.seibel.distanthorizons.core.config.types.enums.*; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.util.StringUtil; @@ -541,18 +542,6 @@ public class Config public static class AdvancedGraphics { - public static ConfigEntry disableFrustumCulling = new ConfigEntry.Builder() - .set(false) - .comment("" - + "If false LODs outside the player's camera \n" - + "aren't drawn, increasing GPU performance. \n" - + "\n" - + "If true all LODs are drawn, even those behind \n" - + "the player's camera, decreasing GPU performance. \n" - + "\n" - + "Disable this if you see LODs disappearing at the corners of your vision.") - .build(); - /** * @deprecated Use overdrawPrevention instead, will be removed when DH updates to MC 1.21
* After removal a float value will be used to control overdraw instead.
@@ -673,6 +662,29 @@ public class Config .setPerformance(EConfigEntryPerformance.NONE) .build(); + public static ConfigEntry disableFrustumCulling = new ConfigEntry.Builder() + .set(false) + .comment("" + + "If false LODs outside the player's camera \n" + + "aren't drawn, increasing GPU performance. \n" + + "\n" + + "If true all LODs are drawn, even those behind \n" + + "the player's camera, decreasing GPU performance. \n" + + "\n" + + "Disable this if you see LODs disappearing at the corners of your vision.") + .build(); + + public static ConfigEntry disableShadowPassFrustumCulling = new ConfigEntry.Builder() + .set(false) + .comment("" + + "Identical to the other frustum culling option\n" + + "only used when a shader mod is present using the DH API\n" + + "and the shadow pass is being rendered.\n" + + "\n" + + "Disable this if shadows render incorrectly.") + .build(); + + } } @@ -1285,6 +1297,26 @@ public class Config .addListener(UnsafeValuesConfigListener.INSTANCE) .build(); + public static ConfigEntry columnBuilderDebugEnable = new ConfigEntry.Builder() + .set(false) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); + public static ConfigEntry columnBuilderDebugDetailLevel = new ConfigEntry.Builder() + .set((int) DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); + public static ConfigEntry columnBuilderDebugXPos = new ConfigEntry.Builder() + .set(0) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); + public static ConfigEntry columnBuilderDebugZPos = new ConfigEntry.Builder() + .set(0) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/DebugColumnConfigEventHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/DebugColumnConfigEventHandler.java new file mode 100644 index 000000000..9e014f45f --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/DebugColumnConfigEventHandler.java @@ -0,0 +1,56 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.config.eventHandlers; + +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.enums.config.EHorizontalQuality; +import com.seibel.distanthorizons.api.enums.config.EMaxHorizontalResolution; +import com.seibel.distanthorizons.api.enums.config.EVerticalQuality; +import com.seibel.distanthorizons.api.enums.config.quickOptions.EQualityPreset; +import com.seibel.distanthorizons.api.enums.rendering.ETransparency; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.config.ConfigEntryWithPresetOptions; +import com.seibel.distanthorizons.core.config.eventHandlers.presets.AbstractPresetConfigEventHandler; +import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener; +import com.seibel.distanthorizons.core.config.listeners.IConfigListener; +import com.seibel.distanthorizons.coreapi.interfaces.config.IConfigEntry; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class DebugColumnConfigEventHandler implements IConfigListener +{ + public static DebugColumnConfigEventHandler INSTANCE = new DebugColumnConfigEventHandler(); + + @Override + public void onConfigValueSet() + { + IDhApiRenderProxy renderProxy = DhApi.Delayed.renderProxy; + if (renderProxy != null) + { + renderProxy.clearRenderDataCache(); + } + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java index ebb7052a4..6b75be291 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java @@ -180,18 +180,22 @@ public class ColumnRenderBufferBuilder // Variable initialization EDebugRendering debugMode = Config.Client.Advanced.Debugging.debugRendering.get(); - // TODO make a config for this - // can be uncommented to limit which section positions are build and thus, rendered + // can be used to limit which section positions are build and thus, rendered // useful when debugging a specific section -// if (renderSource.sectionPos.getDetailLevel() == 6 -// && renderSource.sectionPos.getZ() == 0 && renderSource.sectionPos.getX() == 0) -// { -// int test = 0; -// } -// else -// { -// return; -// } + boolean enableColumnBufferLimit = Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get(); + if (enableColumnBufferLimit) + { + if (renderSource.sectionPos.getDetailLevel() == Config.Client.Advanced.Debugging.columnBuilderDebugDetailLevel.get() + && renderSource.sectionPos.getX() == Config.Client.Advanced.Debugging.columnBuilderDebugXPos.get() + && renderSource.sectionPos.getZ() == Config.Client.Advanced.Debugging.columnBuilderDebugZPos.get()) + { + int test = 0; + } + else + { + return; + } + } byte detailLevel = renderSource.getDataDetailLevel(); for (int x = 0; x < ColumnRenderSource.SECTION_SIZE; x++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java index 6e0c81d27..a3b3d54d1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java @@ -243,6 +243,21 @@ public class FullDataToRenderDataTransformer int id = FullDataPointUtil.getId(fullData); int light = FullDataPointUtil.getLight(fullData); + // TODO how should corrupted data be handled? + // TODO why is the full data corrupted in the first place? FullDataPointUtil hasn't been changed in a long time, could one of the full data point objects be corrupted? + // TODO if either of these happen the ID might also be invalid + //if (bottomY + blockHeight > 300) + //{ + // // this data point is too tall, it's probably a monolith + // int k = 0; + // throw new RuntimeException(); + //} + //if (light > 16 || light < 0) + //{ + // // light is out of range + // throw new RuntimeException(); + //} + IBiomeWrapper biome; IBlockStateWrapper block; try @@ -257,7 +272,11 @@ public class FullDataToRenderDataTransformer { brokenPos.add(fullDataMapping.getPos()); String dimName = level.getLevelWrapper().getDimensionType().getDimensionName(); - LOGGER.warn("Unable to get data point with id ["+id+"] (Max possible ID: ["+fullDataMapping.getMaxValidId()+"]) for pos ["+fullDataMapping.getPos()+"] in dimension ["+dimName+"]. Error: ["+e.getMessage()+"]. Further errors for this position won't be logged."); + LOGGER.warn("Unable to get data point with id ["+id+"] " + + "(Max possible ID: ["+fullDataMapping.getMaxValidId()+"]) " + + "for pos ["+fullDataMapping.getPos()+"] in dimension ["+dimName+"]. " + + "Error: ["+e.getMessage()+"]. " + + "Further errors for this position won't be logged."); } // skip rendering broken data diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractDataSourceHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractDataSourceHandler.java index b87b809c5..8f2ec3440 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractDataSourceHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractDataSourceHandler.java @@ -17,6 +17,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.channels.ClosedChannelException; +import java.util.ArrayList; import java.util.Enumeration; import java.util.Timer; import java.util.TimerTask; @@ -187,8 +188,6 @@ public abstract class AbstractDataSourceHandler updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkDataView) { - DhSectionPos pos = chunkDataView.getSectionPos().convertNewToDetailLevel(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); - ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor(); if (executor == null || executor.isTerminated()) { @@ -199,7 +198,15 @@ public abstract class AbstractDataSourceHandler this.updateDataSourcesRecursively(pos, chunkDataView), executor); + return CompletableFuture.runAsync(() -> + { + DhSectionPos bottomPos = chunkDataView.getSectionPos().convertNewToDetailLevel(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); + + bottomPos.forEachPosUpToDetailLevel( + this.topSectionDetailLevelRef.byteValue(), + (pos) -> this.updateDataSourceAtPos(pos, chunkDataView) ); + + }, executor); } catch (RejectedExecutionException ignore) { @@ -207,26 +214,6 @@ public abstract class AbstractDataSourceHandler this.topSectionDetailLevelRef.get()) - { - return; - } - - - DhSectionPos chunkSectionPos = chunkDataView.getSectionPos(); - LodUtil.assertTrue(chunkSectionPos.overlapsExactly(pos), "Update failed, chunk [" + chunkSectionPos + "] does not overlap section [" + pos + "]."); - - // update this pos - this.updateDataSourceAtPos(pos, chunkDataView); - - // recursively update the parent pos - DhSectionPos parentPos = pos.getParentPos(); - this.updateDataSourcesRecursively(parentPos, chunkDataView); - } protected void updateDataSourceAtPos(DhSectionPos pos, ChunkSizedFullDataAccessor chunkData) { // a lock is necessary to prevent two threads from writing to the same position at once, diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java index 09b848987..7cf65631d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java @@ -106,7 +106,11 @@ public class FullDataFileHandler extends AbstractDataSourceHandler onWorldGenTaskCompleteListeners = new ArrayList<>(); - /** Used to prevent data sources from being garbage collected before their world gen finishes. */ - private final ConcurrentHashMap generatingDataSourceByPos = new ConcurrentHashMap<>(); + /** Used to prevent world gen tasks from being queued multiple times. */ + private final Set generatingDataPos = Collections.newSetFromMap(new ConcurrentHashMap<>()); @@ -69,16 +67,20 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler //===========// @Override - public IFullDataSource get(DhSectionPos pos) + public IFullDataSource get(DhSectionPos pos) { return this.get(pos, true); } + public IFullDataSource get(DhSectionPos pos, boolean runWorldGenCheck) { IFullDataSource dataSource = super.get(pos); - // add world gen tasks for missing columns in the data source - // if this position hasn't already been queued for generation - IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); - if (worldGenQueue != null && !this.generatingDataSourceByPos.containsKey(pos)) + if (runWorldGenCheck) { - this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, pos, dataSource); + // add world gen tasks for missing columns in the data source + // if this position hasn't already been queued for generation + IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + if (worldGenQueue != null && !this.generatingDataPos.contains(pos)) + { + this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, pos, dataSource); + } } return dataSource; @@ -104,7 +106,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler public void clearGenerationQueue() { this.worldGenQueueRef.set(null); - this.generatingDataSourceByPos.clear(); // clear the incomplete data sources + this.generatingDataPos.clear(); // clear the incomplete data sources } /** Can be used to remove positions that are outside the player's render distance. */ @@ -112,11 +114,11 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { HashSet removedRequests = new HashSet<>(); - this.generatingDataSourceByPos.forEach((pos, dataSource) -> + this.generatingDataPos.forEach((pos) -> { if (removeIf.apply(pos)) { - this.generatingDataSourceByPos.remove(pos); + this.generatingDataPos.remove(pos); removedRequests.add(pos); } }); @@ -139,35 +141,33 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler // events // //========// - private void onWorldGenTaskComplete(WorldGenResult genTaskResult, Throwable exception, GenTask genTask, DhSectionPos pos) + private void onWorldGenTaskComplete(WorldGenResult genTaskResult, Throwable exception) { if (exception != null) { // don't log shutdown exceptions if (!(exception instanceof CancellationException || exception.getCause() instanceof CancellationException)) { - LOGGER.error("Uncaught Gen Task Exception at " + pos + ":", exception); + LOGGER.error("Uncaught Gen Task Exception at [" + genTaskResult.pos + "], error: ["+ exception.getMessage() + "].", exception); } } else if (genTaskResult.success) { - this.fireOnGenPosSuccessListeners(pos); + this.fireOnGenPosSuccessListeners(genTaskResult.pos); return; } else { // generation didn't complete - LOGGER.debug("Gen Task Failed at " + pos); + LOGGER.debug("Gen Task Failed at " + genTaskResult.pos); } // if the generation task was split up into smaller positions, add the on-complete event to them for (CompletableFuture siblingFuture : genTaskResult.childFutures) { - siblingFuture.whenComplete((siblingGenTaskResult, siblingEx) -> this.onWorldGenTaskComplete(siblingGenTaskResult, siblingEx, genTask, pos)); + siblingFuture.whenComplete((siblingGenTaskResult, siblingEx) -> this.onWorldGenTaskComplete(siblingGenTaskResult, siblingEx)); } - - genTask.releaseStrongReference(); } private void fireOnGenPosSuccessListeners(DhSectionPos pos) @@ -196,20 +196,21 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler for (DhSectionPos genPos : genPosList) { // try not to re-queue already generating tasks - if (this.generatingDataSourceByPos.containsKey(genPos)) + if (this.generatingDataPos.contains(genPos)) + { + continue; + } + + if (this.repo.existsWithPrimaryKey(genPos.serialize())) { continue; } // queue each new gen task - GenTask genTask = new GenTask(dataSource.getSectionPos(), new WeakReference<>(dataSource)); + GenTask genTask = new GenTask(dataSource.getSectionPos()); CompletableFuture worldGenFuture = worldGenQueue.submitGenTask(genPos, dataSource.getDataDetailLevel(), genTask); - worldGenFuture.whenComplete((genTaskResult, ex) -> - { - this.onWorldGenTaskComplete(genTaskResult, ex, genTask, genPos); - this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos); - }); + worldGenFuture.whenComplete((genTaskResult, ex) -> this.onWorldGenTaskComplete(genTaskResult, ex)); taskFutureList.add(worldGenFuture); } @@ -218,11 +219,11 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler // mark the data source as generating if necessary if (taskFutureList.size() != 0) { - this.generatingDataSourceByPos.put(pos, dataSource); + this.generatingDataPos.add(pos); CompletableFuture.allOf(taskFutureList.toArray(new CompletableFuture[0])) .whenComplete((voidObj, ex) -> { - this.generatingDataSourceByPos.remove(pos); + this.generatingDataPos.remove(pos); }); } } @@ -233,52 +234,29 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler // helper classes // //================// + // TODO may not be needed private class GenTask implements IWorldGenTaskTracker { private final DhSectionPos pos; - // weak reference (probably) used to prevent overloading the GC when lots of gen tasks are created? // TODO do we still need a weak reference here? - private final WeakReference targetFullDataSourceRef; - // the target data source is where the generated chunk data will be put when completed - private IFullDataSource loadedTargetFullDataSource = null; - - - - public GenTask(DhSectionPos pos, WeakReference targetFullDataSourceRef) + public GenTask(DhSectionPos pos) { this.pos = pos; - this.targetFullDataSourceRef = targetFullDataSourceRef; } @Override - public boolean isMemoryAddressValid() { return this.targetFullDataSourceRef.get() != null; } + public boolean isMemoryAddressValid() { return true; } @Override public Consumer getChunkDataConsumer() { - if (this.loadedTargetFullDataSource == null) - { - this.loadedTargetFullDataSource = this.targetFullDataSourceRef.get(); - } - if (this.loadedTargetFullDataSource == null) - { - return null; - } - - return (chunkSizedFullDataSource) -> { - if (chunkSizedFullDataSource.getSectionPos().overlapsExactly(this.loadedTargetFullDataSource.getSectionPos())) - { - ((DhLevel) GeneratedFullDataFileHandler.this.level).updateDataSourcesWithChunkData(chunkSizedFullDataSource); - } + GeneratedFullDataFileHandler.this.level.updateDataSourcesWithChunkData(chunkSizedFullDataSource); }; } - - public void releaseStrongReference() { this.loadedTargetFullDataSource = null; } - } /** used by external event listeners */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java similarity index 89% rename from core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java rename to core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java index bbdcb2e7e..d32518a9b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java @@ -27,18 +27,23 @@ import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import java.util.concurrent.CompletableFuture; -public abstract class DhLevel implements IDhLevel +public abstract class AbstractDhLevel implements IDhLevel { - public final ChunkToLodBuilder chunkToLodBuilder; - protected DhLevel() { this.chunkToLodBuilder = new ChunkToLodBuilder(); } - - public abstract void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor data); - @Override - public int getMinY() { return 0; } + //=============// + // constructor // + //=============// + + protected AbstractDhLevel() { this.chunkToLodBuilder = new ChunkToLodBuilder(); } + + + + //=================// + // default methods // + //=================// @Override public CompletableFuture updateChunkAsync(IChunkWrapper chunk) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index 6052e8f07..ed7e2f014 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -52,7 +52,7 @@ import java.awt.*; import java.io.File; /** The level used when connected to a server */ -public class DhClientLevel extends DhLevel implements IDhClientLevel +public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java index d7da78f41..be70e9f95 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java @@ -38,14 +38,13 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; -import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import org.apache.logging.log4j.Logger; import java.awt.*; import java.util.Iterator; /** The level used on a singleplayer world */ -public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhServerLevel +public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLevel, IDhServerLevel { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index 8212b8a21..7e05f9d89 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -53,7 +53,7 @@ import javax.annotation.CheckForNull; import java.util.Map; import java.util.concurrent.*; -public class DhServerLevel extends DhLevel implements IDhServerLevel +public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java index c97be2d74..ed82b95ae 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java @@ -49,5 +49,6 @@ public interface IDhLevel extends AutoCloseable boolean hasSkyLight(); + void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor data); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index b453ec777..9dbf25ff6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -27,6 +27,7 @@ import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.Nullable; import java.util.function.Consumer; +import java.util.function.Function; /** * The position object used to define LOD objects in the quad trees.

@@ -318,6 +319,21 @@ public class DhSectionPos implements INetworkObject } } + /** Applies the given consumer to all children of the position at the given section detail level. */ + public void forEachChildDownToDetailLevel(byte minSectionDetailLevel, Function callback) + { + boolean stop = callback.apply(this); + if (stop || minSectionDetailLevel == this.detailLevel) + { + return; + } + + for (int i = 0; i < 4; i++) + { + this.getChildByIndex(i).forEachChildDownToDetailLevel(minSectionDetailLevel, callback); + } + } + /** Applies the given consumer to all children of the position at the given section detail level. */ public void forEachChildAtLevel(byte sectionDetailLevel, Consumer callback) { @@ -333,6 +349,20 @@ public class DhSectionPos implements INetworkObject } } + /** Applies the given consumer to all children of the position at the given section detail level. */ + public void forEachPosUpToDetailLevel(byte maxSectionDetailLevel, Consumer callback) + { + callback.accept(this); + if (maxSectionDetailLevel == this.detailLevel) + { + return; + } + + this.getParentPos().forEachPosUpToDetailLevel(maxSectionDetailLevel, callback); + } + + + //===============// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java b/core/src/main/java/com/seibel/distanthorizons/core/render/DhFrustumBounds.java similarity index 97% rename from core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java rename to core/src/main/java/com/seibel/distanthorizons/core/render/DhFrustumBounds.java index 62d3aac75..cf18751b8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/DhFrustumBounds.java @@ -1,4 +1,4 @@ -package com.seibel.distanthorizons.core.pos; +package com.seibel.distanthorizons.core.render; import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum; import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/NeverCullFrustum.java b/core/src/main/java/com/seibel/distanthorizons/core/render/NeverCullFrustum.java new file mode 100644 index 000000000..7e10b0b44 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/NeverCullFrustum.java @@ -0,0 +1,41 @@ +package com.seibel.distanthorizons.core.render; + +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; +import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; + +/** + * Dummy {@link IDhApiCullingFrustum} that allows everything through.
+ * Useful when a frustum is required, but culling shouldn't be done. + */ +public class NeverCullFrustum implements IDhApiCullingFrustum, IDhApiShadowCullingFrustum +{ + //=============// + // constructor // + //=============// + + public NeverCullFrustum() { } + + + + //=========// + // methods // + //=========// + + @Override + public void update(int worldMinBlockY, int worldMaxBlockY, Mat4f dhWorldViewProjection) { /* update isn't needed */ } + + @Override + public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { return true; } + + + + //=====================// + // overridable methods // + //=====================// + + @Override + public int getPriority() { return IOverrideInjector.CORE_PRIORITY; } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java index ac06920ff..8fb1da7a4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java @@ -21,13 +21,14 @@ package com.seibel.distanthorizons.core.render; import com.seibel.distanthorizons.api.DhApi; import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.f3.F3Screen; -import com.seibel.distanthorizons.core.pos.DhFrustumBounds; import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.pos.Pos2D; @@ -35,12 +36,15 @@ import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.objects.SortedArraySet; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector; import com.seibel.distanthorizons.coreapi.util.math.Mat4f; +import com.seibel.distanthorizons.coreapi.util.math.Vec3d; import com.seibel.distanthorizons.coreapi.util.math.Vec3f; import org.apache.logging.log4j.Logger; +import org.joml.Matrix4f; import org.joml.Matrix4fc; import java.util.Comparator; @@ -56,6 +60,8 @@ public class RenderBufferHandler implements AutoCloseable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class); /** contains all relevant data */ @@ -82,14 +88,20 @@ public class RenderBufferHandler implements AutoCloseable public RenderBufferHandler(LodQuadTree lodQuadTree) { this.lodQuadTree = lodQuadTree; - this.culledBufferCount = 0; - IDhApiCullingFrustum coreFrustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY); - if (coreFrustum == null) + IDhApiCullingFrustum coreCameraFrustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY); + if (coreCameraFrustum == null) { DhApi.overrides.bind(IDhApiCullingFrustum.class, new DhFrustumBounds()); } + // by default the shadow pass shouldn't have any frustum culling + IDhApiShadowCullingFrustum coreShadowFrustum = DhApi.overrides.get(IDhApiShadowCullingFrustum.class, IOverrideInjector.CORE_PRIORITY); + if (coreShadowFrustum == null) + { + DhApi.overrides.bind(IDhApiShadowCullingFrustum.class, new NeverCullFrustum()); + } + this.f3Message = new F3Screen.MultiDynamicMessage( () -> @@ -131,7 +143,7 @@ public class RenderBufferHandler implements AutoCloseable * TODO: This might get locked by update() causing move() call. Is there a way to avoid this? * Maybe dupe the base list and use atomic swap on render? Or is this not worth it? */ - public void buildRenderListAndUpdateSections(IClientLevelWrapper clientLevelWrapper, Matrix4fc matWorldViewProjection, Vec3f lookForwardVector) + public void buildRenderListAndUpdateSections(IClientLevelWrapper clientLevelWrapper, DhApiRenderParam renderEventParam, Vec3f lookForwardVector) { EDhDirection[] axisDirections = new EDhDirection[3]; @@ -236,14 +248,42 @@ public class RenderBufferHandler implements AutoCloseable + //====================================// + // get and update the culling frustum // + //====================================// + + // get the culling frustum + boolean enableFrustumCulling; + IDhApiCullingFrustum frustum; + boolean isShadowPass = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isRenderingShadowPass()); + if (isShadowPass) + { + enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableShadowPassFrustumCulling.get(); + frustum = DhApi.overrides.get(IDhApiShadowCullingFrustum.class); + } + else + { + enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get(); + frustum = DhApi.overrides.get(IDhApiCullingFrustum.class); + } + + // update the frustum if necessary - boolean enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get(); - IDhApiCullingFrustum frustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY); if (enableFrustumCulling) { int worldMinY = clientLevelWrapper.getMinHeight(); int worldHeight = clientLevelWrapper.getHeight(); + Vec3d cameraPos = MC_RENDER.getCameraExactPosition(); + + Matrix4fc matWorldView = new Matrix4f() + .setTransposed(renderEventParam.mcModelViewMatrix.getValuesAsArray()) + .translate(-(float) cameraPos.x, -(float) cameraPos.y, -(float) cameraPos.z); + + Matrix4fc matWorldViewProjection = new Matrix4f() + .setTransposed(renderEventParam.dhProjectionMatrix.getValuesAsArray()) + .mul(matWorldView); + frustum.update(worldMinY, worldMinY + worldHeight, new Mat4f(matWorldViewProjection)); } @@ -253,7 +293,6 @@ public class RenderBufferHandler implements AutoCloseable // Update the section list // //=========================// - boolean isShadowPass = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isRenderingShadowPass()); if (isShadowPass) { this.shadowCulledBufferCount = 0; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index dac8d049b..6f2148976 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -351,14 +351,7 @@ public class LodRenderer if (renderingFirstPass) { - Matrix4f matWorldView = new Matrix4f() - .setTransposed(MC_RENDER.getWorldViewMatrix().getValuesAsArray()); - - Matrix4fc matWorldViewProjection = new Matrix4f() - .setTransposed(renderEventParam.dhProjectionMatrix.getValuesAsArray()) - .mul(matWorldView); - - this.bufferHandler.buildRenderListAndUpdateSections(clientLevelWrapper, matWorldViewProjection, MC_RENDER.getLookAtVector()); + this.bufferHandler.buildRenderListAndUpdateSections(clientLevelWrapper, renderEventParam, MC_RENDER.getLookAtVector()); transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled; fakeOceanFloor = Config.Client.Advanced.Graphics.Quality.transparency.get().fakeTransparencyEnabled; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java index 220441779..eb871c92b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java @@ -96,8 +96,8 @@ public class SSAOApplyShader extends AbstractShaderRenderer if (this.gFarUniform >= 0) { - float far = (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2)); - GL32.glUniform1f(this.gFarUniform, far); + float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks(); + GL32.glUniform1f(this.gFarUniform, farClipPlane); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/sql/DbConnectionClosedException.java b/core/src/main/java/com/seibel/distanthorizons/core/sql/DbConnectionClosedException.java index 75a8b769d..b4e8cffb0 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/sql/DbConnectionClosedException.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/sql/DbConnectionClosedException.java @@ -20,7 +20,7 @@ public class DbConnectionClosedException extends SQLException { // TODO long term we should prevent using repos that are closed, but for now this is the easier solution String message = e.getMessage().toLowerCase(); - return message.contains("connection closed") || message.contains("pointer is closed"); + return message.contains("connection closed") || message.contains("pointer is closed") || message.contains("database has been closed"); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java index 344c58dd8..773707bad 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java @@ -832,8 +832,8 @@ public class RenderDataPointReducingList return RenderDataPointUtil.createVoidDataPoint(); } - long highest; - int lowest; + long highestDataPoint; + long lowestDataPoint; int index = 0; //first loop: find the first visible segment. foundVisible: @@ -843,8 +843,8 @@ public class RenderDataPointReducingList long dataPoint = view.get(index); if (isDataVisible(dataPoint)) { - highest = dataPoint; - lowest = RenderDataPointUtil.getYMin(dataPoint); + highestDataPoint = dataPoint; + lowestDataPoint = dataPoint; break foundVisible; } } @@ -858,13 +858,15 @@ public class RenderDataPointReducingList long dataPoint = view.get(index); if (isDataVisible(dataPoint)) { - int y = RenderDataPointUtil.getYMin(dataPoint); - if (y > highest) highest = dataPoint; - else if (y < lowest) lowest = y; + int yMax = RenderDataPointUtil.getYMax(dataPoint); + int yMin = RenderDataPointUtil.getYMin(dataPoint); + + if (yMax > RenderDataPointUtil.getYMax(highestDataPoint)) highestDataPoint = dataPoint; + else if (yMin < RenderDataPointUtil.getYMin(lowestDataPoint)) lowestDataPoint = dataPoint; } } - return (highest & ~RenderDataPointUtil.DEPTH_SHIFTED_MASK) | ((lowest & RenderDataPointUtil.DEPTH_MASK) << RenderDataPointUtil.DEPTH_SHIFT); + return (highestDataPoint & ~RenderDataPointUtil.DEPTH_SHIFTED_MASK) | (RenderDataPointUtil.getYMin(lowestDataPoint) << RenderDataPointUtil.DEPTH_SHIFT); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java index 4d00bf0e7..1a110fc2a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java @@ -19,7 +19,7 @@ package com.seibel.distanthorizons.core.util; -import com.seibel.distanthorizons.core.level.DhLevel; +import com.seibel.distanthorizons.core.level.AbstractDhLevel; import com.seibel.distanthorizons.core.logging.SpamReducedLogger; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.IColumnDataView; @@ -174,9 +174,9 @@ public class RenderDataPointUtil return dataPoint & ~(HEIGHT_SHIFTED_MASK | DEPTH_SHIFTED_MASK) | height | depth; } - /** AKA the ending/top/highest Y value above {@link DhLevel#getMinY()} */ + /** AKA the ending/top/highest Y value above {@link AbstractDhLevel#getMinY()} */ public static short getYMax(long dataPoint) { return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK); } - /** AKA the starting/bottom/lowest Y value above {@link DhLevel#getMinY()} */ + /** AKA the starting/bottom/lowest Y value above {@link AbstractDhLevel#getMinY()} */ public static short getYMin(long dataPoint) { return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK); } public static short getAlpha(long dataPoint) { return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java index d3cbd2097..4f4352643 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java @@ -147,14 +147,13 @@ public class RenderUtil { // in James' testing a near clip plane distance of 2 blocks is enough to allow the fragment // culling to take effect instead of seeing the near clip plane. - float nearClipDist = 2f; //MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH / 4.0f; //getNearClipPlaneDistanceInBlocks(partialTicks); + float nearClipDist = RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks); if (Config.Client.Advanced.Debugging.lodOnlyMode.get()) { nearClipDist = 0.1f; } - int farPlaneDistanceInBlocks = RenderUtil.getFarClipPlaneDistanceInBlocks(); - float farClipDist = (float) ((farPlaneDistanceInBlocks + LodUtil.REGION_WIDTH) * Math.sqrt(2)); + float farClipDist = (float) RenderUtil.getFarClipPlaneDistanceInBlocks(); // Create a copy of the current matrix, so it won't be modified. Mat4f lodProj = mcProjMat.copy(); @@ -228,7 +227,9 @@ public class RenderUtil public static int getFarClipPlaneDistanceInBlocks() { int lodChunkDist = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get(); - return lodChunkDist * LodUtil.CHUNK_WIDTH; + int lodBlockDist = lodChunkDist * LodUtil.CHUNK_WIDTH; + // sqrt 2 to prevent the corners from being cut off + return (int)((lodBlockDist + LodUtil.REGION_WIDTH) * Math.sqrt(2)); } /** @return false if LODs shouldn't be rendered for any reason */ diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index 5545e9bd0..677155555 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -265,10 +265,6 @@ "distanthorizons.config.client.advanced.graphics.advancedGraphics": "Advanced Graphics Options", - "distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling": - "Disable Frustum Culling", - "distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling.@tooltip": - "If false LODs outside the player's camera \naren't drawn, increasing GPU performance. \n\nIf true all LODs are drawn, even those behind \nthe player's camera, decreasing GPU performance. \n\nDisable this if you see LODs disappearing at the corners of your vision.", "distanthorizons.config.client.advanced.graphics.advancedGraphics.overdrawPrevention": "Overdraw Prevention", "distanthorizons.config.client.advanced.graphics.advancedGraphics.overdrawPrevention.@tooltip": @@ -305,7 +301,15 @@ "LOD Shading", "distanthorizons.config.client.advanced.graphics.advancedGraphics.lodShading.@tooltip": "Defines how LODs should be shaded. \nCan be used to improve shader compatibility.", - + "distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling": + "Disable Frustum Culling", + "distanthorizons.config.client.advanced.graphics.advancedGraphics.disableFrustumCulling.@tooltip": + "If false LODs outside the player's camera \naren't drawn, increasing GPU performance. \n\nIf true all LODs are drawn, even those behind \nthe player's camera, decreasing GPU performance. \n\nDisable this if you see LODs disappearing at the corners of your vision.", + "distanthorizons.config.client.advanced.graphics.advancedGraphics.disableShadowPassFrustumCulling": + "Disable Shadow Pass Frustum Culling", + "distanthorizons.config.client.advanced.graphics.advancedGraphics.disableShadowPassFrustumCulling.@tooltip": + "Identical to the other frustum culling option except that it is \nonly used when a shader mod is present using the DH API \nand the shadow pass is being rendered. \n\nDisable this if shadows render incorrectly.", + "distanthorizons.config.client.advanced.worldGenerator": "World Generator", @@ -454,6 +458,15 @@ "distanthorizons.config.client.advanced.debugging.allowUnsafeValues.@tooltip": "If enabled, very limited config input validation will be performed. \n\nWarning: enabling this can cause instability or crashing, use at your own risk. \nNote: this option isn't saved between sessions.", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugEnable": + "Enable Column Builder Limiting", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugDetailLevel": + "Column Builder Limit - Detail Level", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugXPos": + "Column Builder Limit - X Pos", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugZPos": + "Column Builder Limit - Z Pos", + "distanthorizons.config.client.advanced.buffers": "Buffers",