Merge DetailDistanceUtil into LodQuadTree
This commit is contained in:
-3
@@ -5,9 +5,7 @@ import com.seibel.lod.api.enums.config.EHorizontalResolution;
|
||||
import com.seibel.lod.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.listeners.IConfigListener;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@@ -83,7 +81,6 @@ public class RenderCacheConfigEventHandler implements IConfigListener
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
DetailDistanceUtil.updateSettings();
|
||||
DhApiMain.Delayed.renderProxy.clearRenderDataCache();
|
||||
}
|
||||
};
|
||||
|
||||
-5
@@ -1,12 +1,7 @@
|
||||
package com.seibel.lod.core.config.eventHandlers;
|
||||
|
||||
import com.seibel.lod.api.DhApiMain;
|
||||
import com.seibel.lod.api.enums.config.EHorizontalResolution;
|
||||
import com.seibel.lod.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.lod.core.config.listeners.IConfigListener;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
|
||||
public class ResetConfigEventHandler
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.pos.DhLodPos;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.lod.core.util.FileScanUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.coreapi.util.math.Mat4f;
|
||||
@@ -86,7 +85,7 @@ public abstract class AbstractDhClientLevel implements IDhClientLevel
|
||||
|
||||
// TODO this should probably be handled via a config change listener
|
||||
// recreate the RenderState if the render distance changes
|
||||
if (clientRenderState.quadtree.blockRenderDistance != Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
|
||||
if (clientRenderState.quadtree.blockRenderDistanceRadius != Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
|
||||
{
|
||||
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
|
||||
{
|
||||
|
||||
@@ -9,14 +9,14 @@ import com.seibel.lod.core.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.file.renderfile.ILodRenderSourceProvider;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadTree;
|
||||
import com.seibel.lod.coreapi.util.MathUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
public final int blockRenderDistance;
|
||||
public final int blockRenderDistanceRadius;
|
||||
private final ILodRenderSourceProvider renderSourceProvider;
|
||||
|
||||
/**
|
||||
@@ -37,31 +37,39 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
* This is a {@link ConcurrentLinkedQueue} because new sections can be added to this list via the world generator threads.
|
||||
*/
|
||||
private final ConcurrentLinkedQueue<DhSectionPos> sectionsToReload = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference!
|
||||
|
||||
private final ConfigChangeListener<EHorizontalQuality> horizontalScaleChangeListener;
|
||||
private final ReentrantLock treeReadWriteLock = new ReentrantLock();
|
||||
|
||||
private ReentrantLock treeReadWriteLock = new ReentrantLock();
|
||||
/** the lowest detail level number that can be rendered */
|
||||
private byte maxRenderDetailLevel;
|
||||
/** used to calculate when a detail drop will occur */
|
||||
private double detailDropOffDistanceUnit;
|
||||
/** used to calculate when a detail drop will occur */
|
||||
private double detailDropOffLogBase;
|
||||
|
||||
|
||||
|
||||
public LodQuadTree(
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public LodQuadTree(
|
||||
IDhClientLevel level, int viewDistanceInBlocks,
|
||||
int initialPlayerBlockX, int initialPlayerBlockZ,
|
||||
ILodRenderSourceProvider provider)
|
||||
{
|
||||
super(viewDistanceInBlocks, new DhBlockPos2D(initialPlayerBlockX, initialPlayerBlockZ), TREE_LOWEST_DETAIL_LEVEL);
|
||||
|
||||
DetailDistanceUtil.updateSettings(); //TODO: Move this to somewhere else
|
||||
this.level = level;
|
||||
this.renderSourceProvider = provider;
|
||||
this.blockRenderDistance = viewDistanceInBlocks;
|
||||
this.blockRenderDistanceRadius = viewDistanceInBlocks;
|
||||
|
||||
this.horizontalScaleChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.horizontalQuality, (newHorizontalScale) -> this.onHorizontalQualityChange());
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// tick update //
|
||||
//=============//
|
||||
@@ -80,6 +88,10 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
}
|
||||
|
||||
|
||||
|
||||
// this shouldn't be updated while the tree is being iterated through
|
||||
this.updateDetailLevelVariables();
|
||||
|
||||
// don't traverse the tree if it is being modified
|
||||
if (this.treeReadWriteLock.tryLock())
|
||||
{
|
||||
@@ -286,33 +298,48 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
* @param sectionPos section position
|
||||
* @return detail level of this section pos
|
||||
*/
|
||||
public byte calculateExpectedDetailLevel(DhBlockPos2D playerPos, DhSectionPos sectionPos)
|
||||
public byte calculateExpectedDetailLevel(DhBlockPos2D playerPos, DhSectionPos sectionPos) { return getDetailLevelFromDistance(playerPos.dist(sectionPos.getCenter().getCenterBlockPos())); }
|
||||
private byte getDetailLevelFromDistance(double distance)
|
||||
{
|
||||
return DetailDistanceUtil.getDetailLevelFromDistance(playerPos.dist(sectionPos.getCenter().getCenterBlockPos()));
|
||||
// special case, never drop the quality
|
||||
if (Config.Client.Advanced.Graphics.Quality.horizontalQuality.get() == EHorizontalQuality.UNLIMITED)
|
||||
{
|
||||
return this.maxRenderDetailLevel;
|
||||
}
|
||||
|
||||
|
||||
double maxDetailDistance = this.getDrawDistanceFromDetail(Byte.MAX_VALUE -1);
|
||||
if (distance > maxDetailDistance)
|
||||
{
|
||||
return Byte.MAX_VALUE - 1;
|
||||
}
|
||||
|
||||
|
||||
int detailLevel = (int) (Math.log(distance / this.detailDropOffDistanceUnit) / this.detailDropOffLogBase);
|
||||
return (byte) MathUtil.clamp(this.maxRenderDetailLevel, detailLevel, Byte.MAX_VALUE - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method will return the highest detail level in a circle around the center
|
||||
* Override this method if you want to use a different algorithm
|
||||
* Note: the returned distance should always be the ceiling estimation of the distance
|
||||
* //TODO: Make this input a bbox or a circle or something....
|
||||
* @param distance the circle radius
|
||||
* @return the highest detail level in the circle
|
||||
*/
|
||||
public byte getMaxDetailInRange(double distance) { return DetailDistanceUtil.getDetailLevelFromDistance(distance); }
|
||||
|
||||
/**
|
||||
* The method will return the furthest distance to the center for the given detail level
|
||||
* Override this method if you want to use a different algorithm
|
||||
* Note: the returned distance should always be the ceiling estimation of the distance
|
||||
* //TODO: Make this return a bbox instead of a distance in circle
|
||||
* @param detailLevel detail level
|
||||
* @return the furthest distance to the center, in blocks
|
||||
*/
|
||||
public int getFurthestDistance(byte detailLevel)
|
||||
private double getDrawDistanceFromDetail(int detail)
|
||||
{
|
||||
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel + 1));
|
||||
// +1 because that's the border to the next detail level, and we want to include up to it.
|
||||
if (detail <= this.maxRenderDetailLevel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (detail >= Byte.MAX_VALUE)
|
||||
{
|
||||
return this.blockRenderDistanceRadius * 2;
|
||||
}
|
||||
|
||||
|
||||
double base = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase;
|
||||
return Math.pow(base, detail) * this.detailDropOffDistanceUnit;
|
||||
}
|
||||
|
||||
private void updateDetailLevelVariables()
|
||||
{
|
||||
this.maxRenderDetailLevel = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
this.detailDropOffDistanceUnit = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().distanceUnitInBlocks * LodUtil.CHUNK_WIDTH;
|
||||
this.detailDropOffLogBase = Math.log(Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase);
|
||||
}
|
||||
|
||||
|
||||
@@ -333,13 +360,6 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
{
|
||||
LOGGER.info("Clearing render cache...");
|
||||
|
||||
|
||||
// changing this while the tree is being traversed can cause (harmless) errors,
|
||||
// where the traversal goes deeper into the tree than it should.
|
||||
// so it should also be inside the tree lock
|
||||
DetailDistanceUtil.updateSettings();
|
||||
|
||||
|
||||
// clear the tree
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.util;
|
||||
|
||||
import com.seibel.lod.api.enums.config.EHorizontalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.render.LodQuadTree;
|
||||
import com.seibel.lod.coreapi.util.MathUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Leonardo Amato
|
||||
* @version ??
|
||||
*/
|
||||
// TODO move this into LodQuadTree? If so then the update method should only be called when the tree isn't being updated
|
||||
@Deprecated
|
||||
public class DetailDistanceUtil
|
||||
{
|
||||
/** smallest numerical detail level */
|
||||
private static byte maxDetailLevel = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
|
||||
/** largest numerical detail level */
|
||||
private static final byte minDetailLevel = Byte.MAX_VALUE;
|
||||
private static final double minDistance = 0;
|
||||
|
||||
// TODO merge with updateSettings() below
|
||||
private static double distanceUnit = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().distanceUnitInBlocks * LodUtil.CHUNK_WIDTH;
|
||||
private static double maxDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH * 2;
|
||||
private static double logBase = Math.log(Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase);
|
||||
|
||||
|
||||
|
||||
/** can cause issues if called while the {@link LodQuadTree} is being iterated through */
|
||||
public static void updateSettings()
|
||||
{
|
||||
maxDetailLevel = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
|
||||
distanceUnit = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().distanceUnitInBlocks * LodUtil.CHUNK_WIDTH;
|
||||
maxDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH * 2;
|
||||
logBase = Math.log(Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase);
|
||||
}
|
||||
|
||||
public static double getDrawDistanceFromDetail(int detail) { return baseDistanceFunction(detail); }
|
||||
private static double baseDistanceFunction(int detail)
|
||||
{
|
||||
if (detail <= maxDetailLevel)
|
||||
{
|
||||
return minDistance;
|
||||
}
|
||||
else if (detail >= minDetailLevel)
|
||||
{
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
|
||||
double base = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase;
|
||||
return Math.pow(base, detail) * distanceUnit;
|
||||
}
|
||||
|
||||
public static byte getDetailLevelFromDistance(double distance) { return baseInverseFunction(distance); }
|
||||
private static byte baseInverseFunction(double distance)
|
||||
{
|
||||
// special case, never drop the quality
|
||||
if (Config.Client.Advanced.Graphics.Quality.horizontalQuality.get() == EHorizontalQuality.UNLIMITED)
|
||||
{
|
||||
return maxDetailLevel;
|
||||
}
|
||||
|
||||
|
||||
double maxDetailDistance = getDrawDistanceFromDetail(minDetailLevel -1);
|
||||
if (distance > maxDetailDistance)
|
||||
{
|
||||
return minDetailLevel - 1;
|
||||
}
|
||||
|
||||
|
||||
int detailLevel = (int) (Math.log(distance / distanceUnit) / logBase);
|
||||
return (byte) MathUtil.clamp(maxDetailLevel, detailLevel, minDetailLevel - 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import com.seibel.lod.core.pos.DhLodPos;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.pos.Pos2D;
|
||||
import com.seibel.lod.coreapi.util.BitShiftUtil;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.coreapi.util.MathUtil;
|
||||
import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
@@ -47,7 +46,6 @@ public class QuadTree<T>
|
||||
*/
|
||||
public QuadTree(int widthInBlocks, DhBlockPos2D centerBlockPos, byte treeMinDetailLevel)
|
||||
{
|
||||
DetailDistanceUtil.updateSettings(); //TODO: Move this to somewhere else
|
||||
this.centerBlockPos = centerBlockPos;
|
||||
this.widthInBlocks = widthInBlocks;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.seibel.lod.core.level.IDhLevel;
|
||||
import com.seibel.lod.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.level.states.ClientRenderState;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.ThreadUtil;
|
||||
import com.seibel.lod.core.util.objects.EventLoop;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -102,7 +101,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
|
||||
if (clientRenderState != null && clientRenderState.quadtree != null)
|
||||
{
|
||||
if (clientRenderState.quadtree.blockRenderDistance != newBlockRenderDistance)
|
||||
if (clientRenderState.quadtree.blockRenderDistanceRadius != newBlockRenderDistance)
|
||||
{
|
||||
// TODO is this the best way to handle changing the render distance?
|
||||
level.close();
|
||||
@@ -111,7 +110,6 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
}
|
||||
}
|
||||
|
||||
DetailDistanceUtil.updateSettings();
|
||||
this.levels.values().forEach(DhClientLevel::clientTick);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user