Fixed Overdraw, mergeVertData error, wrong vanillaDist math.

This commit is contained in:
tom lee
2022-01-07 15:50:42 +08:00
parent 5ac51dd2a5
commit cba75123c7
10 changed files with 103 additions and 103 deletions
@@ -96,7 +96,7 @@ public class EventApi
public void chunkLoadEvent(IChunkWrapper chunk, IDimensionTypeWrapper dimType)
{
ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, dimType, DistanceGenerationMode.FULL);
ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, dimType, DistanceGenerationMode.FULL, true);
}
public void worldSaveEvent()
@@ -461,21 +461,22 @@ public class LodBufferBuilderFactory
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkX;
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkZ;
// Currently fixing below
// FIXME: We don't need to ignore rendered chunks! Just build it and leave it for the renderer to decide!
//We don't want to render this fake block if
//The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered
//
//The block is in the player chunk or in a chunk adjacent to the player
//if(isThisPositionGoingToBeRendered(detailLevel, posX, posZ, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance))
//{
// continue;
//}
// TODO: In the future, We don't need to ignore rendered chunks! Just build it and leave it for the renderer to decide!
// We don't want to render this fake block if
// The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered
// The block is in the player chunk or in a chunk adjacent to the player
if(detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL &&
isThisPositionGoingToBeRendered(LevelPosUtil.getChunkPos(detailLevel, posX),
LevelPosUtil.getChunkPos(detailLevel, posZ)))
{
continue;
}
//we check if the block to render is not in player chunk
boolean posNotInPlayerChunk = !(chunkXdist == 0 && chunkZdist == 0);
// We extract the adj data in the four cardinal direction
// We extract the adj data in the four cardinal direction
// we first reset the adjShadeDisabled. This is used to disable the shade on the border when we have transparent block like water or glass
// to avoid having a "darker border" underground
@@ -558,31 +559,20 @@ public class LodBufferBuilderFactory
return true;
}
// Will be removed in a1.7
@Deprecated
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, int chunkPosX, int chunkPosZ, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
private boolean isThisPositionGoingToBeRendered(int chunkX, int chunkZ){
MovableGridList<Boolean> chunkGrid = ClientApi.renderer.vanillaRenderedChunks;
Boolean isRendered = chunkGrid.get(chunkX, chunkZ);
// skip any chunks that Minecraft is going to render
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - chunkPosX;
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - chunkPosZ;
if (isRendered == null || !isRendered) return false;
// check if the chunk is on the border
boolean isItBorderPos;
if (CONFIG.client().graphics().advancedGraphics().getVanillaOverdraw() == VanillaOverdraw.BORDER)
isItBorderPos = LodUtil.isBorderChunk(vanillaRenderedChunks, chunkXdist + gameChunkRenderDistance + 1, chunkZdist + gameChunkRenderDistance + 1);
return !LodUtil.isBorderChunk(ClientApi.renderer.vanillaRenderedChunks, chunkX, chunkZ);
else
isItBorderPos = false;
//boolean smallRenderDistance = gameChunkRenderDistance <= LodUtil.MINIMUM_RENDER_DISTANCE_FOR_PARTIAL_OVERDRAW;
// get the positions that will be rendered
return (gameChunkRenderDistance >= Math.abs(chunkXdist)
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
&& (!isItBorderPos);
return true;
}
@@ -90,10 +90,10 @@ public class LodBuilder
public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim)
{
generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.FULL);
generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.FULL, false);
}
public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, DistanceGenerationMode generationMode)
public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, DistanceGenerationMode generationMode, boolean override)
{
if (lodWorld == null || lodWorld.getIsWorldNotLoaded())
return;
@@ -130,7 +130,7 @@ public class LodBuilder
{
lodDim = lodWorld.getLodDimension(dim);
}
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode));
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode), override);
//}
//catch (IllegalArgumentException | NullPointerException e)
//{
@@ -149,14 +149,14 @@ public class LodBuilder
*/
public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk) throws IllegalArgumentException
{
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig());
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(), false);
}
/**
* Creates a LodNode for a chunk in the given world.
* @throws IllegalArgumentException thrown if either the chunk or world is null.
*/
public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config)
public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config, boolean override)
throws IllegalArgumentException
{
//long executeTime = System.currentTimeMillis();
@@ -204,7 +204,9 @@ public class LodBuilder
{
posX = LevelPosUtil.convert((byte) 0, chunk.getChunkPosX() * 16 + startX, minDetailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getChunkPosZ() * 16 + startZ, minDetailLevel);
if (!lodDim.doesDataExist(minDetailLevel, posX, posZ)) {
long oldData = lodDim.getSingleData(minDetailLevel, posX, posZ);
if (override || !DataPointUtil.doesItExist(oldData) ||
DataPointUtil.getGenerationMode(oldData)<config.distanceGenerationMode.complexity) {
lodDim.addVerticalData(minDetailLevel, posX, posZ, data);
lodDim.updateData(minDetailLevel, posX, posZ);
}
@@ -266,7 +266,7 @@ public class LodDimensionFileHandler
// (Corresponding call is the this::writerMain(...)::...setRelease(false);)
//boolean haventStarted = !isFileWritingThreadRunning.compareAndExchangeAcquire(false, true);
// The above needs java 9!
boolean haventStarted = !isFileWritingThreadRunning.compareAndSet(false, true);
boolean haventStarted = isFileWritingThreadRunning.compareAndSet(false, true);
if (haventStarted) {
// We acquired the atomic lock.
@@ -152,6 +152,7 @@ public class VertexOptimizer
* This is a map from Direction to the relative normal vector
* we are using this since I'm not sure if the getNormal create new object at every call
*/
// FIXME: No. It doesn't. Just remove this.
@SuppressWarnings("serial")
public static final Map<LodDirection, Vec3i> DIRECTION_NORMAL_MAP = new HashMap<LodDirection, Vec3i>()
{{
@@ -210,14 +210,14 @@ public class VerticalLevelContainer implements LevelContainer
}
private static long[] downgradeVerticalSize(int oldVertSize, int newVertSize, long[] data) {
long[] dataToMerge = new long[oldVertSize];
int size = data.length/oldVertSize;
long[] dataToMerge = new long[oldVertSize];
long[] newData = new long[size * newVertSize];
for (int i = 0; i < size; i++)
{
System.arraycopy(oldVertSize, i * oldVertSize, dataToMerge, 0, oldVertSize);
dataToMerge = DataPointUtil.mergeMultiData(dataToMerge, oldVertSize, newVertSize);
System.arraycopy(dataToMerge, 0, newData, i * newVertSize, newVertSize);
System.arraycopy(data, i * oldVertSize, dataToMerge, 0, oldVertSize);
long[] tempBuffer = DataPointUtil.mergeMultiData(dataToMerge, oldVertSize, newVertSize);
System.arraycopy(tempBuffer, 0, newData, i * newVertSize, newVertSize);
}
return newData;
}
@@ -59,21 +59,6 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
*/
public class LodRenderer
{
public static class VanillaRenderedChunksList extends GridList<Boolean> {
private static final long serialVersionUID = -5448501880911391315L;
public final int centerX;
public final int centerZ;
public VanillaRenderedChunksList(int range, int centerX, int centerZ) {
super(range);
this.centerX = centerX;
this.centerZ = centerZ;
for (int i=0; i<gridSize*gridSize; i++) {
add(i, false);
}
}
}
public static class LagSpikeCatcher {
long timer = System.nanoTime();
@@ -109,7 +94,7 @@ public class LodRenderer
LodRenderProgram shaderProgram = null;
/** This is used to determine if the LODs should be regenerated */
private AbstractBlockPosWrapper previousPos = null;
private AbstractBlockPosWrapper lastUpdatedPos = null;
// these variables are used to determine if the buffers should be rebuilt
private int prevRenderDistance = 0;
@@ -133,7 +118,7 @@ public class LodRenderer
* This HashSet contains every chunk that Vanilla Minecraft
* is going to render
*/
public VanillaRenderedChunksList vanillaRenderedChunks;
public MovableGridList<Boolean> vanillaRenderedChunks;
public int vanillaRenderedChunksCenterX;
public int vanillaRenderedChunksCenterZ;
public int vanillaRenderedChunksRefreshTimer;
@@ -504,50 +489,43 @@ public class LodRenderer
// returns whether anything changed
private boolean updateVanillaRenderedChunks(LodDimension lodDim, boolean recreateChunks) {
short chunkRenderDistance = (short) MC_RENDER.getRenderDistance();
int chunkX = Math.floorDiv(previousPos.getX(), 16);
int chunkZ = Math.floorDiv(previousPos.getZ(), 16);
int chunkX = Math.floorDiv(lastUpdatedPos.getX(), 16);
int chunkZ = Math.floorDiv(lastUpdatedPos.getZ(), 16);
// if the player is high enough, draw all LODs
if (previousPos.getY() > 256) {
vanillaRenderedChunks = new VanillaRenderedChunksList(
if (lastUpdatedPos.getY() > 256) {
vanillaRenderedChunks = new MovableGridList<Boolean>(
chunkRenderDistance, chunkX, chunkZ);
return true;
}
VanillaRenderedChunksList chunkList;
if (recreateChunks) {
vanillaRenderedChunks = new VanillaRenderedChunksList(chunkRenderDistance, chunkX, chunkZ);
return true;
} else {
chunkList = vanillaRenderedChunks;
chunkX = chunkList.centerX;
chunkZ = chunkList.centerZ;
chunkRenderDistance = (short) vanillaRenderedChunks.gridCentreToEdge;
}
MovableGridList<Boolean> chunkList;
boolean anyChanged = false;
if (recreateChunks || vanillaRenderedChunks.gridCentreToEdge != chunkRenderDistance) {
chunkList = new MovableGridList<Boolean>(chunkRenderDistance, chunkX, chunkZ);
anyChanged = true;
} else {
// anyChanged = vanillaRenderedChunks.move(chunkX, chunkZ);
// chunkList = vanillaRenderedChunks;
chunkList = new MovableGridList<Boolean>(chunkRenderDistance, chunkX, chunkZ);
anyChanged = true;
}
LagSpikeCatcher getChunks = new LagSpikeCatcher();
Set<AbstractChunkPosWrapper> chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, previousPos);
Set<AbstractChunkPosWrapper> chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, lastUpdatedPos);
getChunks.end("LodDrawSetup:UpdateStatus:UpdateVanillaChunks:getChunks");
for (AbstractChunkPosWrapper pos : chunkPosToSkip)
{
int xIndex = (pos.getX() - chunkX) + (chunkRenderDistance + 1);
int zIndex = (pos.getZ() - chunkZ) + (chunkRenderDistance + 1);
// sometimes we are given chunks that are outside the render distance,
// This prevents index out of bounds exceptions
if (xIndex >= 0 && zIndex >= 0
&& xIndex < vanillaRenderedChunks.gridSize
&& zIndex < vanillaRenderedChunks.gridSize)
if (!chunkList.inRange(pos.getX(), pos.getZ())) continue;
Boolean oldBool = chunkList.swap(pos.getX(), pos.getZ(), true);
if (oldBool == null || !oldBool)
{
if (!chunkList.get(chunkList.calculateOffset(xIndex, zIndex)))
{
chunkList.set(chunkList.calculateOffset(xIndex, zIndex), true);
anyChanged = true;
lodDim.markRegionBufferToRegen(pos.getRegionX(), pos.getRegionZ());
}
anyChanged = true;
lodDim.markRegionBufferToRegen(pos.getRegionX(), pos.getRegionZ());
}
}
vanillaRenderedChunks = chunkList;
if (anyChanged) vanillaRenderedChunks = chunkList;
return anyChanged;
}
@@ -577,12 +555,12 @@ public class LodRenderer
// check if the player has moved
if (newTime - prevPlayerPosTime > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveTimeout) {
if (previousPos == null
|| Math.abs(newPos.getX() - previousPos.getX()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16
|| Math.abs(newPos.getZ() - previousPos.getZ()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16)
if (lastUpdatedPos == null
|| Math.abs(newPos.getX() - lastUpdatedPos.getX()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16
|| Math.abs(newPos.getZ() - lastUpdatedPos.getZ()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16)
{
tryPartialGen = true;
previousPos = newPos;
lastUpdatedPos = newPos;
posUpdated = true;
}
prevPlayerPosTime = newTime;
@@ -604,7 +582,7 @@ public class LodRenderer
if (tryFullGen && !posUpdated) {
previousPos = newPos;
lastUpdatedPos = newPos;
posUpdated = true;
}
shouldUpdateChunks |= posUpdated;
@@ -394,6 +394,7 @@ public class LodUtil
* @param z relative (to the matrix) z chunk to check
* @return true if and only if the chunk is a border of the renderable chunks
*/
@Deprecated
public static boolean isBorderChunk(boolean[][] vanillaRenderedChunks, int x, int z)
{
if (x < 0 || z < 0 || x >= vanillaRenderedChunks.length || z >= vanillaRenderedChunks[0].length)
@@ -410,6 +411,17 @@ public class LodUtil
}
return false;
}
public static boolean isBorderChunk(MovableGridList<Boolean> vanillaRenderedChunks, int chunkX, int chunkZ)
{
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
{
int tempX = chunkX + lodDirection.getNormal().x;
int tempZ = chunkZ + lodDirection.getNormal().z;
Boolean b = vanillaRenderedChunks.get(tempX, tempZ);
if (b == null || !b) return true;
}
return false;
}
/** This is copied from Minecraft's MathHelper class */
@@ -67,11 +67,25 @@ public class MovableGridList<T> extends ArrayList<T> implements List<T> {
}
// return null if x,y is outside of the grid
// Otherwise, return the new value (for chaining)
public T setAndGet(int x, int y, T t) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return _setDirect(x,y, t) ? t : null;
}
// return null if x,y is outside of the grid
// Otherwise, return the old value
public T swap(int x, int y, T t) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return _swapDirect(x,y, t);
}
public boolean inRange(int x, int y) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return (x>=0 && x<gridSize && y>=0 && y<gridSize);
}
private final T _getDirect(int x, int y) {
if (x<0 || x>=gridSize || y<0 || y>=gridSize) return null;
@@ -82,9 +96,14 @@ public class MovableGridList<T> extends ArrayList<T> implements List<T> {
super.set(x + y * gridSize, t);
return true;
}
private final T _swapDirect(int x, int y, T t) {
if (x<0 || x>=gridSize || y<0 || y>=gridSize) return null;
return super.set(x + y * gridSize, t);
}
public void move(int newCenterX, int newCenterY) {
if (centerX == newCenterX && centerY == newCenterY) return;
// Return false if haven't changed. Return true if it did
public boolean move(int newCenterX, int newCenterY) {
if (centerX == newCenterX && centerY == newCenterY) return false;
int deltaX = newCenterX - centerX;
int deltaY = newCenterY - centerY;
@@ -97,7 +116,7 @@ public class MovableGridList<T> extends ArrayList<T> implements List<T> {
// update the new center
centerX = newCenterX;
centerY = newCenterY;
return;
return true;
}
centerX = newCenterX;
centerY = newCenterY;
@@ -147,6 +166,7 @@ public class MovableGridList<T> extends ArrayList<T> implements List<T> {
}
}
}
return true;
}
public void move(int newCenterX, int newCenterY, Consumer<? super T> d) {
@@ -101,9 +101,6 @@ public interface IMinecraftRenderWrapper
IWrapperFactory factory = SingletonHandler.get(IWrapperFactory.class);
int chunkRenderDist = this.getRenderDistance();
// if we have a odd render distance, we'll have a empty gap. This way we'll overlap by 1 instead,
// which is preferable to having a hole in the world
chunkRenderDist = chunkRenderDist % 2 == 0 ? chunkRenderDist : chunkRenderDist - 1;
AbstractChunkPosWrapper centerChunkPos = mcWrapper.getPlayerChunkPos();
int startChunkX = centerChunkPos.getX() - chunkRenderDist;
@@ -111,9 +108,9 @@ public interface IMinecraftRenderWrapper
// add every position within render distance
HashSet<AbstractChunkPosWrapper> renderedPos = new HashSet<AbstractChunkPosWrapper>();
for (int chunkX = 0; chunkX < (chunkRenderDist * 2); chunkX++)
for (int chunkX = 0; chunkX < (chunkRenderDist * 2+1); chunkX++)
{
for(int chunkZ = 0; chunkZ < (chunkRenderDist * 2); chunkZ++)
for(int chunkZ = 0; chunkZ < (chunkRenderDist * 2+1); chunkZ++)
{
renderedPos.add(factory.createChunkPos(startChunkX + chunkX, startChunkZ + chunkZ));
}