diff --git a/src/main/java/com/seibel/lod/core/enums/config/DropoffQuality.java b/src/main/java/com/seibel/lod/core/enums/config/DropoffQuality.java
new file mode 100644
index 000000000..271c8c68b
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/enums/config/DropoffQuality.java
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Distant Horizon mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2022 Tom Lee (TomTheFurry)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * SMOOTH_DROPOFF
+ * PERFORMANCE_FOCUSED
+ *
+ * Determines how lod level drop off should be done
+ *
+ * @author Tom Lee
+ * @version 7-1-2022
+ */
+public enum DropoffQuality {
+
+ /** SMOOTH_DROPOFF when <128 lod view distance, or PERFORMANCE_FOCUSED otherwise */
+ AUTO(-1),
+
+ SMOOTH_DROPOFF(10),
+
+ PERFORMANCE_FOCUSED(0);
+
+ public final int fastModeSwitch;
+
+ DropoffQuality(int fastModeSwitch) {
+ this.fastModeSwitch = fastModeSwitch;
+ }
+
+
+}
diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java
index b249e95fe..3b59af3ce 100644
--- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java
+++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java
@@ -26,6 +26,7 @@ import java.util.concurrent.Executors;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
+import com.seibel.lod.core.enums.config.DropoffQuality;
import com.seibel.lod.core.enums.config.GenerationPriority;
import com.seibel.lod.core.enums.config.VerticalQuality;
import com.seibel.lod.core.handlers.LodDimensionFileHandler;
@@ -385,7 +386,11 @@ public class LodDimension
DistanceGenerationMode generationMode = CONFIG.client().worldGenerator().getDistanceGenerationMode();
VerticalQuality verticalQuality = CONFIG.client().graphics().quality().getVerticalQuality();
-
+ DropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getDropoffQuality();
+ if (dropoffQuality == DropoffQuality.AUTO)
+ dropoffQuality = CONFIG.client().graphics().quality().getLodChunkRenderDistance() < 128 ?
+ DropoffQuality.SMOOTH_DROPOFF : DropoffQuality.PERFORMANCE_FOCUSED;
+ int dropoffSwitch = dropoffQuality.fastModeSwitch;
// don't run the expander multiple times
// for the same location
Runnable thread = () -> {
@@ -423,10 +428,10 @@ public class LodDimension
region = getRegionFromFile(regions[x][z], minDetail, generationMode, verticalQuality);
regions[x][z] = region;
updated = true;
- } else if (region.lastMaxDetailLevel != maxDetail) {
+ } else if (minDetail <= dropoffSwitch && region.lastMaxDetailLevel != maxDetail) {
region.lastMaxDetailLevel = maxDetail;
updated = true;
- } else if (region.lastMaxDetailLevel != region.getMinDetailLevel()) {
+ } else if (minDetail <= dropoffSwitch && region.lastMaxDetailLevel != region.getMinDetailLevel()) {
updated = true;
}
if (updated) {
@@ -503,11 +508,16 @@ public class LodDimension
GenerationPriority generationPriority = CONFIG.client().worldGenerator().getGenerationPriority();
if (generationPriority == GenerationPriority.AUTO)
generationPriority = MC.hasSinglePlayerServer() ? GenerationPriority.FAR_FIRST : GenerationPriority.NEAR_FIRST;
+
+ DropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getDropoffQuality();
+ if (dropoffQuality == DropoffQuality.AUTO)
+ dropoffQuality = CONFIG.client().graphics().quality().getLodChunkRenderDistance() < 128 ?
+ DropoffQuality.SMOOTH_DROPOFF : DropoffQuality.PERFORMANCE_FOCUSED;
boolean requireCorrectDetailLevel = generationPriority == GenerationPriority.NEAR_FIRST;
if (region != null)
- region.getPosToRender(posToRender, playerPosX, playerPosZ, requireCorrectDetailLevel);
+ region.getPosToRender(posToRender, playerPosX, playerPosZ, requireCorrectDetailLevel, dropoffQuality);
}
/**
diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java
index 936d16d21..b5dc6a9aa 100644
--- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java
+++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java
@@ -20,6 +20,7 @@
package com.seibel.lod.core.objects.lod;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
+import com.seibel.lod.core.enums.config.DropoffQuality;
import com.seibel.lod.core.enums.config.GenerationPriority;
import com.seibel.lod.core.enums.config.VerticalQuality;
import com.seibel.lod.core.objects.PosToGenerateContainer;
@@ -192,7 +193,6 @@ public class LodRegion {
int childPosX = childOffsetPosX * 2;
int childPosZ = childOffsetPosZ * 2;
- int childSize = 1 << (LodUtil.REGION_DETAIL_LEVEL - childDetailLevel);
byte targetDetailLevel = DetailDistanceUtil.getGenerationDetailFromDistance(minDistance);
if (targetDetailLevel <= detailLevel) {
@@ -233,9 +233,15 @@ public class LodRegion {
* understand
*/
public void getPosToRender(PosToRenderContainer posToRender, int playerPosX, int playerPosZ,
- boolean requireCorrectDetailLevel) {
- getPosToRender(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ,
- requireCorrectDetailLevel);
+ boolean requireCorrectDetailLevel, DropoffQuality dropoffQuality) {
+ int minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ, regionPosX, regionPosZ);
+ byte targetLevel = DetailDistanceUtil.getDrawDetailFromDistance(minDistance);
+ if (targetLevel <= dropoffQuality.fastModeSwitch) {
+ getPosToRender(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ,
+ requireCorrectDetailLevel);
+ } else {
+ getPosToRenderFlat(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, targetLevel, requireCorrectDetailLevel);
+ }
}
/**
@@ -305,6 +311,47 @@ public class LodRegion {
}
}
+ /**
+ * This method will fill the posToRender array with all levelPos that are
+ * render-able. But the entire region try use the same detail level.
+ */
+ private void getPosToRenderFlat(PosToRenderContainer posToRender, byte detailLevel, int posX, int posZ, byte targetLevel, boolean requireCorrectDetailLevel) {
+ // equivalent to 2^(...)
+ int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
+
+ if (detailLevel == targetLevel) {
+ posToRender.addPosToRender(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size);
+ } else // case where (detailLevel > desiredLevel)
+ {
+ int childPosX = posX * 2;
+ int childPosZ = posZ * 2;
+ byte childDetailLevel = (byte) (detailLevel - 1);
+ int childrenCount = 0;
+
+ for (int x = 0; x <= 1; x++) {
+ for (int z = 0; z <= 1; z++) {
+ if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z)) {
+ if (!requireCorrectDetailLevel)
+ childrenCount++;
+ else
+ getPosToRenderFlat(posToRender, childDetailLevel, childPosX + x, childPosZ + z, targetLevel, requireCorrectDetailLevel);
+ }
+ }
+ }
+
+ if (!requireCorrectDetailLevel) {
+ // If all the four children exist go deeper
+ if (childrenCount == 4) {
+ for (int x = 0; x <= 1; x++)
+ for (int z = 0; z <= 1; z++)
+ getPosToRenderFlat(posToRender, childDetailLevel, childPosX + x, childPosZ + z, targetLevel, requireCorrectDetailLevel);
+ } else {
+ posToRender.addPosToRender(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size);
+ }
+ }
+ }
+ }
+
/**
* Updates all children.
*
diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index 8b2d8092a..00da18d5c 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -22,6 +22,7 @@ package com.seibel.lod.core.wrapperInterfaces.config; import com.seibel.lod.core.enums.config.BlocksToAvoid; import com.seibel.lod.core.enums.config.BufferRebuildTimes; import com.seibel.lod.core.enums.config.DistanceGenerationMode; +import com.seibel.lod.core.enums.config.DropoffQuality; import com.seibel.lod.core.enums.config.GenerationPriority; import com.seibel.lod.core.enums.config.GpuUploadMethod; import com.seibel.lod.core.enums.config.HorizontalQuality; @@ -140,6 +141,21 @@ public interface ILodConfigWrapperSingleton + " Highest Quality: " + HorizontalQuality.HIGH; HorizontalQuality getHorizontalQuality(); void setHorizontalQuality(HorizontalQuality newHorizontalQuality); + + DropoffQuality DROPOFF_QUALITY_DEFAULT = DropoffQuality.AUTO; + String DROPOFF_QUALITY_DESC = "" + + " This determines how lod level drop off will be done. \n" + + "\n" + + " " + DropoffQuality.SMOOTH_DROPOFF + ": \n" + + " The lod level is calculated for each point, making the drop off a smooth circle. \n" + + " " + DropoffQuality.PERFORMANCE_FOCUSED + ": \n" + + " One detail level for an entire region. Minimize CPU usage and \n" + + " improve terrain refresh delay, especially for high Lod render distance. \n" + + " " + DropoffQuality.AUTO + ": \n" + + " Use "+ DropoffQuality.SMOOTH_DROPOFF + " for less then 128 Lod render distance, \n" + + " or "+ DropoffQuality.PERFORMANCE_FOCUSED +" otherwise. \n"; + DropoffQuality getDropoffQuality(); + void setDropoffQuality(DropoffQuality newDropoffQuality); } interface IFogQuality