added a borderChunk finder function
This commit is contained in:
@@ -295,10 +295,12 @@ public class LodBufferBuilder
|
||||
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x;
|
||||
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z;
|
||||
|
||||
boolean isItBorderPos = LodUtil.isBorderChunk(vanillaRenderedChunks,chunkXdist + gameChunkRenderDistance + 1,chunkZdist + gameChunkRenderDistance + 1);
|
||||
if (gameChunkRenderDistance >= Math.abs(chunkXdist)
|
||||
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
|
||||
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
|
||||
&& vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
|
||||
&& vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
|
||||
&& !isItBorderPos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -316,7 +318,8 @@ public class LodBufferBuilder
|
||||
&& posToRender.contains(detailLevel, xAdj, zAdj)
|
||||
&& (gameChunkRenderDistance < Math.abs(chunkXdist)
|
||||
|| gameChunkRenderDistance < Math.abs(chunkZdist)
|
||||
|| !vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]))
|
||||
|| !(vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
|
||||
&& !LodUtil.isBorderChunk(vanillaRenderedChunks,chunkXdist + gameChunkRenderDistance + 1,chunkZdist + gameChunkRenderDistance + 1))))
|
||||
{
|
||||
if (!adjData.containsKey(direction) || adjData.get(direction) == null)
|
||||
adjData.put(direction, new long[maxVerticalData]);
|
||||
@@ -442,7 +445,7 @@ public class LodBufferBuilder
|
||||
drawableVbos[x][z] = new VertexBuffer[1];
|
||||
} else
|
||||
{
|
||||
numberOfBuffers = (int) Math.ceil(memoryRequired / BUFFER_MAX_CAPACITY)+1;
|
||||
numberOfBuffers = (int) Math.ceil(memoryRequired / BUFFER_MAX_CAPACITY) + 1;
|
||||
System.out.println(numberOfBuffers);
|
||||
memoryRequired = BUFFER_MAX_CAPACITY;
|
||||
bufferSize[x][z] = numberOfBuffers;
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.seibel.lod.render;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.seibel.lod.builders.bufferBuilding.lodTemplates.Box;
|
||||
import net.minecraft.util.Direction;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL15C;
|
||||
@@ -58,6 +60,7 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import org.lwjgl.system.CallbackI;
|
||||
|
||||
|
||||
/**
|
||||
@@ -74,7 +77,7 @@ public class LodRenderer
|
||||
* it should be something different than what is used by Minecraft
|
||||
*/
|
||||
private static final int LOD_GL_LIGHT_NUMBER = GL11.GL_LIGHT2;
|
||||
|
||||
|
||||
/**
|
||||
* If true the LODs colors will be replaced with
|
||||
* a checkerboard, this can be used for debugging.
|
||||
@@ -97,15 +100,16 @@ public class LodRenderer
|
||||
*/
|
||||
private VertexBuffer[][][] vbos;
|
||||
public static final VertexFormat LOD_VERTEX_FORMAT = DefaultVertexFormats.POSITION_COLOR;
|
||||
private ChunkPos vbosCenter = new ChunkPos(0,0);
|
||||
private ChunkPos vbosCenter = new ChunkPos(0, 0);
|
||||
|
||||
|
||||
/**
|
||||
* This is used to determine if the LODs should be regenerated
|
||||
*/
|
||||
private int[] previousPos = new int[]{0,0,0};
|
||||
|
||||
private int[] previousPos = new int[]{0, 0, 0};
|
||||
|
||||
public NativeImage lightMap = null;
|
||||
|
||||
|
||||
// these variables are used to determine if the buffers should be rebuilt
|
||||
private long prevDayTime = 0;
|
||||
private double prevBrightness = 0;
|
||||
@@ -148,9 +152,9 @@ public class LodRenderer
|
||||
* Besides drawing the LODs this method also starts
|
||||
* the async process of generating the Buffers that hold those LODs.
|
||||
*
|
||||
* @param lodDim The dimension to draw, if null doesn't replace the current dimension.
|
||||
* @param lodDim The dimension to draw, if null doesn't replace the current dimension.
|
||||
* @param mcMatrixStack This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method
|
||||
* @param partialTicks how far into the current tick this method was called.
|
||||
* @param partialTicks how far into the current tick this method was called.
|
||||
*/
|
||||
public void drawLODs(LodDimension lodDim, MatrixStack mcMatrixStack, float partialTicks, IProfiler newProfiler)
|
||||
{
|
||||
@@ -168,8 +172,8 @@ public class LodRenderer
|
||||
|
||||
profiler = newProfiler;
|
||||
profiler.push("LOD setup");
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead)
|
||||
// starting here...
|
||||
determineIfLodsShouldRegenerate(lodDim);
|
||||
@@ -197,12 +201,11 @@ public class LodRenderer
|
||||
|
||||
// TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead)
|
||||
// ...ending here
|
||||
|
||||
|
||||
if (lodBufferBuilder.newBuffersAvaliable())
|
||||
{
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
@@ -210,7 +213,7 @@ public class LodRenderer
|
||||
//===========================//
|
||||
|
||||
// set the required open GL settings
|
||||
|
||||
|
||||
if (LodConfig.CLIENT.debugging.debugMode.get() == DebugMode.SHOW_DETAIL_WIREFRAME)
|
||||
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
|
||||
else
|
||||
@@ -233,7 +236,7 @@ public class LodRenderer
|
||||
// OpenGl outputs their matricies in col,row form instead of row,col
|
||||
// (or maybe vice versa I have no idea :P)
|
||||
mcProjectionMatrix.transpose();
|
||||
|
||||
|
||||
Matrix4f modelViewMatrix = offsetTheModelViewMatrix(mcMatrixStack, partialTicks);
|
||||
|
||||
// required for setupFog and setupProjectionMatrix
|
||||
@@ -256,16 +259,16 @@ public class LodRenderer
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
|
||||
|
||||
profiler.popPush("LOD draw");
|
||||
|
||||
|
||||
if (vbos != null)
|
||||
{
|
||||
ActiveRenderInfo renderInfo = mc.getGameRenderer().getMainCamera();
|
||||
Vector3d cameraDir = new Vector3d(renderInfo.getLookVector());
|
||||
|
||||
|
||||
boolean cullingDisabled = LodConfig.CLIENT.graphics.disableDirectionalCulling.get();
|
||||
|
||||
|
||||
// used to determine what type of fog to render
|
||||
int halfWidth = vbos.length / 2;
|
||||
int quarterWidth = vbos.length / 4;
|
||||
@@ -283,7 +286,7 @@ public class LodRenderer
|
||||
setupFog(fogSettings.far.distance, fogSettings.far.quality);
|
||||
|
||||
|
||||
for(int i = 0; i < lodBufferBuilder.bufferSize[x][z]; i++)
|
||||
for (int i = 0; i < lodBufferBuilder.bufferSize[x][z]; i++)
|
||||
{
|
||||
sendLodsToGpuAndDraw(vbos[x][z][i], modelViewMatrix);
|
||||
}
|
||||
@@ -291,7 +294,7 @@ public class LodRenderer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// cleanup //
|
||||
@@ -314,11 +317,11 @@ public class LodRenderer
|
||||
// reset the projection matrix so anything drawn after
|
||||
// the LODs will use the correct projection matrix
|
||||
gameRender.resetProjectionMatrix(mcProjectionMatrix);
|
||||
|
||||
|
||||
// clear the depth buffer so anything drawn is drawn
|
||||
// over the LODs
|
||||
GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
||||
|
||||
// end of internal LOD profiling
|
||||
profiler.pop();
|
||||
@@ -332,13 +335,13 @@ public class LodRenderer
|
||||
{
|
||||
if (vbo == null)
|
||||
return;
|
||||
|
||||
|
||||
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id);
|
||||
// 0L is the starting pointer
|
||||
LOD_VERTEX_FORMAT.setupBufferState(0L);
|
||||
|
||||
|
||||
vbo.draw(modelViewMatrix, GL11.GL_QUADS);
|
||||
|
||||
|
||||
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
LOD_VERTEX_FORMAT.clearBufferState();
|
||||
}
|
||||
@@ -369,8 +372,7 @@ public class LodRenderer
|
||||
{
|
||||
// fancy fog (fragment distance based fog)
|
||||
glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
// fast fog (frustum distance based fog)
|
||||
glFogDistanceMode = NVFogDistance.GL_EYE_PLANE_ABSOLUTE_NV;
|
||||
@@ -388,16 +390,16 @@ public class LodRenderer
|
||||
if (fogQuality == FogQuality.FANCY)
|
||||
{
|
||||
// for more realistic fog when using FAR
|
||||
if(LodConfig.CLIENT.graphics.fogDistance.get() == FogDistance.NEAR_AND_FAR)
|
||||
if (LodConfig.CLIENT.graphics.fogDistance.get() == FogDistance.NEAR_AND_FAR)
|
||||
{
|
||||
RenderSystem.fogStart(farPlaneBlockDistance * 0.9f);
|
||||
RenderSystem.fogEnd(farPlaneBlockDistance * 1.0f);
|
||||
}else{
|
||||
} else
|
||||
{
|
||||
RenderSystem.fogStart(farPlaneBlockDistance * 0.1f);
|
||||
RenderSystem.fogEnd(farPlaneBlockDistance * 1.0f);
|
||||
}
|
||||
}
|
||||
else if (fogQuality == FogQuality.FAST)
|
||||
} else if (fogQuality == FogQuality.FAST)
|
||||
{
|
||||
// for the far fog of the normal chunks
|
||||
// to start right where the LODs' end use:
|
||||
@@ -405,15 +407,13 @@ public class LodRenderer
|
||||
RenderSystem.fogStart(farPlaneBlockDistance * 1.5f);
|
||||
RenderSystem.fogEnd(farPlaneBlockDistance * 2.0f);
|
||||
}
|
||||
}
|
||||
else if (fogDistance == FogDistance.NEAR)
|
||||
} else if (fogDistance == FogDistance.NEAR)
|
||||
{
|
||||
if (fogQuality == FogQuality.FANCY)
|
||||
{
|
||||
RenderSystem.fogEnd(mc.getRenderDistance() * 16 * 1.41f);
|
||||
RenderSystem.fogStart(mc.getRenderDistance() * 16 * 1.6f);
|
||||
}
|
||||
else if (fogQuality == FogQuality.FAST)
|
||||
} else if (fogQuality == FogQuality.FAST)
|
||||
{
|
||||
RenderSystem.fogEnd(mc.getRenderDistance() * 16 * 1.0f);
|
||||
RenderSystem.fogStart(mc.getRenderDistance() * 16 * 1.5f);
|
||||
@@ -461,12 +461,12 @@ public class LodRenderer
|
||||
{
|
||||
// duplicate the last matrix
|
||||
mcMatrixStack.pushPose();
|
||||
|
||||
|
||||
|
||||
|
||||
// get all relevant camera info
|
||||
ActiveRenderInfo renderInfo = mc.getGameRenderer().getMainCamera();
|
||||
Vector3d projectedView = renderInfo.getPosition();
|
||||
|
||||
|
||||
// translate the camera relative to the regions' center
|
||||
// (AxisAlignedBoundingBoxes (LODs) use doubles and thus have a higher
|
||||
// accuracy vs the model view matrix, which only uses floats)
|
||||
@@ -475,73 +475,75 @@ public class LodRenderer
|
||||
double xDiff = eyePos.x - bufferPos.getX();
|
||||
double zDiff = eyePos.z - bufferPos.getZ();
|
||||
mcMatrixStack.translate(-xDiff, -projectedView.y, -zDiff);
|
||||
|
||||
|
||||
|
||||
|
||||
// get the modified model view matrix
|
||||
Matrix4f lodModelViewMatrix = mcMatrixStack.last().pose();
|
||||
Matrix4f lodModelViewMatrix = mcMatrixStack.last().pose();
|
||||
// remove the lod ModelViewMatrix
|
||||
mcMatrixStack.popPose();
|
||||
|
||||
|
||||
return lodModelViewMatrix;
|
||||
}
|
||||
|
||||
|
||||
/** James added this to test if Vivecraft is not using
|
||||
* the MC FOV setting or if the problem is deeper */
|
||||
/**
|
||||
* James added this to test if Vivecraft is not using
|
||||
* the MC FOV setting or if the problem is deeper
|
||||
*/
|
||||
public enum FovTest
|
||||
{
|
||||
LOD_USE_FOV(true, false),
|
||||
MC_USE_FOV(false, true),
|
||||
NEITHER(false, false),
|
||||
BOTH(true, true);
|
||||
|
||||
|
||||
boolean lodProjUseFov;
|
||||
boolean defaultMcProjUseFov;
|
||||
|
||||
|
||||
private FovTest(boolean newLodProjUseFov, boolean newDefaultMcProjUseFov)
|
||||
{
|
||||
lodProjUseFov = newLodProjUseFov;
|
||||
defaultMcProjUseFov = newDefaultMcProjUseFov;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create a new projection matrix and send it over to the GPU
|
||||
*
|
||||
*
|
||||
* @param currentProjectionMatrix this is Minecraft's current projection matrix
|
||||
* @param partialTicks how many ticks into the frame we are
|
||||
* @param partialTicks how many ticks into the frame we are
|
||||
*/
|
||||
private void setupProjectionMatrix(Matrix4f currentProjectionMatrix, float partialTicks)
|
||||
{
|
||||
// create the new projection matrix
|
||||
Matrix4f lodPoj =
|
||||
Matrix4f.perspective(
|
||||
getFov(partialTicks, LodConfig.CLIENT.graphics.useFovSetting.get().lodProjUseFov),
|
||||
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
|
||||
mc.getRenderDistance()/2,
|
||||
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH * 2 / 4);
|
||||
|
||||
Matrix4f.perspective(
|
||||
getFov(partialTicks, LodConfig.CLIENT.graphics.useFovSetting.get().lodProjUseFov),
|
||||
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
|
||||
mc.getRenderDistance() / 2,
|
||||
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH * 2 / 4);
|
||||
|
||||
// get Minecraft's un-edited projection matrix
|
||||
// (this is before it is zoomed, distorted, etc.)
|
||||
Matrix4f defaultMcProj = mc.getGameRenderer().getProjectionMatrix(mc.getGameRenderer().getMainCamera(), partialTicks, LodConfig.CLIENT.graphics.useFovSetting.get().defaultMcProjUseFov);
|
||||
// true here means use "use fov setting" (probably)
|
||||
|
||||
|
||||
|
||||
|
||||
// this logic strips away the defaultMcProj matrix so we
|
||||
// can get the distortionMatrix, which represents all
|
||||
// transformations, zooming, distortions, etc. done
|
||||
// to Minecraft's Projection matrix
|
||||
Matrix4f defaultMcProjInv = defaultMcProj.copy();
|
||||
defaultMcProjInv.invert();
|
||||
|
||||
|
||||
Matrix4f distortionMatrix = defaultMcProjInv.copy();
|
||||
distortionMatrix.multiply(currentProjectionMatrix);
|
||||
|
||||
|
||||
|
||||
|
||||
// edit the lod projection to match Minecraft's
|
||||
// (so the LODs line up with the real world)
|
||||
lodPoj.multiply(distortionMatrix);
|
||||
|
||||
|
||||
// send the projection over to the GPU
|
||||
gameRender.resetProjectionMatrix(lodPoj);
|
||||
}
|
||||
@@ -616,7 +618,7 @@ public class LodRenderer
|
||||
/**
|
||||
* Replace the current Vertex Buffers with the newly
|
||||
* created buffers from the lodBufferBuilder. <br><br>
|
||||
*
|
||||
* <p>
|
||||
* For some reason this has to be called after the frame has been rendered,
|
||||
* otherwise visual stuttering/rubber banding may happen. I'm not sure why...
|
||||
*/
|
||||
@@ -758,27 +760,27 @@ public class LodRenderer
|
||||
*/
|
||||
private void determineIfLodsShouldRegenerate(LodDimension lodDim)
|
||||
{
|
||||
|
||||
|
||||
short chunkRenderDistance = (short) mc.getRenderDistance();
|
||||
|
||||
int vanillaRenderedChunksWidth = chunkRenderDistance*2+2;
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
|
||||
|
||||
|
||||
int vanillaRenderedChunksWidth = chunkRenderDistance * 2 + 2;
|
||||
|
||||
//=============//
|
||||
// full regens //
|
||||
//=============//
|
||||
|
||||
|
||||
// check if the view distance changed
|
||||
if (ClientProxy.previousLodRenderDistance != LodConfig.CLIENT.graphics.lodChunkRenderDistance.get()
|
||||
|| mc.getRenderDistance() != prevRenderDistance
|
||||
|| chunkRenderDistance != prevRenderDistance
|
||||
|| prevFogDistance != LodConfig.CLIENT.graphics.fogDistance.get())
|
||||
{
|
||||
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
DetailDistanceUtil.updateSettings();
|
||||
fullRegen = true;
|
||||
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
|
||||
prevFogDistance = LodConfig.CLIENT.graphics.fogDistance.get();
|
||||
prevRenderDistance = mc.getRenderDistance();
|
||||
prevRenderDistance = chunkRenderDistance;
|
||||
}
|
||||
|
||||
// did the user change the debug setting?
|
||||
@@ -791,7 +793,7 @@ public class LodRenderer
|
||||
|
||||
long newTime = System.currentTimeMillis();
|
||||
|
||||
if(LodConfig.CLIENT.graphics.detailDropOff.get() == DetailDropOff.FANCY)
|
||||
if (LodConfig.CLIENT.graphics.detailDropOff.get() == DetailDropOff.FANCY)
|
||||
{
|
||||
// check if the player has moved
|
||||
if (newTime - prevPlayerPosTime > LodConfig.CLIENT.buffers.bufferRebuildPlayerMoveTimeout.get())
|
||||
@@ -800,6 +802,7 @@ public class LodRenderer
|
||||
|| mc.getPlayer().xChunk != LevelPosUtil.getPosX(previousPos)
|
||||
|| mc.getPlayer().zChunk != LevelPosUtil.getPosZ(previousPos))
|
||||
{
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
fullRegen = true;
|
||||
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
|
||||
}
|
||||
@@ -808,7 +811,6 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// partial regens //
|
||||
//================//
|
||||
@@ -848,8 +850,6 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// LOD skipping //
|
||||
//==============//
|
||||
@@ -862,11 +862,11 @@ public class LodRenderer
|
||||
{
|
||||
xIndex = (pos.x - mc.getPlayer().xChunk) + (chunkRenderDistance + 1);
|
||||
zIndex = (pos.z - mc.getPlayer().zChunk) + (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.length
|
||||
&& xIndex < vanillaRenderedChunks.length
|
||||
&& zIndex < vanillaRenderedChunks.length)
|
||||
{
|
||||
if (!vanillaRenderedChunks[xIndex][zIndex])
|
||||
@@ -877,8 +877,8 @@ public class LodRenderer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// if the player is high enough, draw all LODs
|
||||
if(chunkPosToSkip.isEmpty() && mc.getPlayer().position().y > 256)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.seibel.lod.builders.bufferBuilding.lodTemplates.Box;
|
||||
import com.seibel.lod.enums.LodTemplate;
|
||||
import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.objects.RegionPos;
|
||||
@@ -30,6 +31,7 @@ import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.client.renderer.WorldRenderer;
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher.CompiledChunk;
|
||||
import net.minecraft.server.integrated.IntegratedServer;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.DimensionType;
|
||||
@@ -42,26 +44,32 @@ import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
/**
|
||||
* This class holds methods and constants that may be used in multiple places.
|
||||
*
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 9-7-2021
|
||||
*/
|
||||
public class LodUtil
|
||||
{
|
||||
private static MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
|
||||
|
||||
/** alpha used when drawing chunks in debug mode */
|
||||
|
||||
|
||||
/**
|
||||
* alpha used when drawing chunks in debug mode
|
||||
*/
|
||||
public static final int DEBUG_ALPHA = 255; // 0 - 255
|
||||
public static final Color COLOR_DEBUG_BLACK = new Color(0, 0, 0, DEBUG_ALPHA);
|
||||
public static final Color COLOR_DEBUG_WHITE = new Color(255, 255, 255, DEBUG_ALPHA);
|
||||
public static final Color COLOR_INVISIBLE = new Color(0,0,0,0);
|
||||
|
||||
/** a gray-purple color */
|
||||
public static final Color COLOR_INVISIBLE = new Color(0, 0, 0, 0);
|
||||
|
||||
/**
|
||||
* a gray-purple color
|
||||
*/
|
||||
public static final int MYCELIUM_COLOR_INT = LodUtil.colorToInt(Color.decode("#6E6166"));
|
||||
/** TODO, add a better way to override material colors
|
||||
/**
|
||||
* TODO, add a better way to override material colors
|
||||
* and/or add a method to generate colors based on texture
|
||||
* issue #64 */
|
||||
* issue #64
|
||||
*/
|
||||
public static final int STONE_COLOR_INT = LodUtil.colorToInt(new Color(150, 150, 150));
|
||||
public static final int NETHERRACK_COLOR_INT = LodUtil.colorToInt(new Color(95, 38, 38));
|
||||
public static final int WARPED_NYLIUM_COLOR_INT = LodUtil.colorToInt(new Color(34, 94, 85));
|
||||
@@ -71,14 +79,20 @@ public class LodUtil
|
||||
* In order of nearest to farthest: <br>
|
||||
* Red, Orange, Yellow, Green, Cyan, Blue, Magenta, white, gray, black
|
||||
*/
|
||||
public static final Color DEBUG_DETAIL_LEVEL_COLORS[] = new Color[] { Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.WHITE, Color.GRAY, Color.BLACK };
|
||||
|
||||
|
||||
/** 512 blocks wide */
|
||||
public static final Color DEBUG_DETAIL_LEVEL_COLORS[] = new Color[]{Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.WHITE, Color.GRAY, Color.BLACK};
|
||||
|
||||
|
||||
/**
|
||||
* 512 blocks wide
|
||||
*/
|
||||
public static final byte REGION_DETAIL_LEVEL = 9;
|
||||
/** 16 blocks wide */
|
||||
/**
|
||||
* 16 blocks wide
|
||||
*/
|
||||
public static final byte CHUNK_DETAIL_LEVEL = 4;
|
||||
/** 1 block wide */
|
||||
/**
|
||||
* 1 block wide
|
||||
*/
|
||||
public static final byte BLOCK_DETAIL_LEVEL = 0;
|
||||
|
||||
|
||||
@@ -86,28 +100,40 @@ public class LodUtil
|
||||
|
||||
public static final short MAX_VERTICAL_DATA = 4;
|
||||
|
||||
/** measured in Blocks <br>
|
||||
* detail level 9 */
|
||||
/**
|
||||
* measured in Blocks <br>
|
||||
* detail level 9
|
||||
*/
|
||||
public static final short REGION_WIDTH = 512;
|
||||
/** measured in Blocks <br>
|
||||
* detail level 4 */
|
||||
/**
|
||||
* measured in Blocks <br>
|
||||
* detail level 4
|
||||
*/
|
||||
public static final short CHUNK_WIDTH = 16;
|
||||
/** measured in Blocks <br>
|
||||
* detail level 0 */
|
||||
/**
|
||||
* measured in Blocks <br>
|
||||
* detail level 0
|
||||
*/
|
||||
public static final short BLOCK_WIDTH = 1;
|
||||
|
||||
|
||||
/** number of chunks wide */
|
||||
|
||||
|
||||
/**
|
||||
* number of chunks wide
|
||||
*/
|
||||
public static final int REGION_WIDTH_IN_CHUNKS = 32;
|
||||
|
||||
|
||||
/** If we ever need to use a heightmap for any reason, use this one. */
|
||||
|
||||
|
||||
/**
|
||||
* If we ever need to use a heightmap for any reason, use this one.
|
||||
*/
|
||||
public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG;
|
||||
|
||||
/** This regex finds any characters that are invalid for use in a windows
|
||||
* (and by extension mac and linux) file path */
|
||||
|
||||
/**
|
||||
* This regex finds any characters that are invalid for use in a windows
|
||||
* (and by extension mac and linux) file path
|
||||
*/
|
||||
public static final String INVALID_FILE_CHARACTERS_REGEX = "[\\\\\\/:*?\\\"<>|]";
|
||||
|
||||
|
||||
/**
|
||||
* 64 MB by default is the maximum amount of memory that
|
||||
* can be directly allocated. <br><br>
|
||||
@@ -120,33 +146,29 @@ public class LodUtil
|
||||
* https://stackoverflow.com/questions/50499238/bytebuffer-allocatedirect-and-xmx
|
||||
*/
|
||||
public static final int MAX_ALOCATEABLE_DIRECT_MEMORY = 64 * 1024 * 1024;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the first valid ServerWorld.
|
||||
*
|
||||
*
|
||||
* @return null if there are no ServerWorlds
|
||||
*/
|
||||
public static ServerWorld getFirstValidServerWorld()
|
||||
{
|
||||
if (mc.hasSingleplayerServer())
|
||||
return null;
|
||||
|
||||
|
||||
Iterable<ServerWorld> worlds = mc.getSingleplayerServer().getAllLevels();
|
||||
|
||||
|
||||
for (ServerWorld world : worlds)
|
||||
return world;
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the ServerWorld for the relevant dimension.
|
||||
*
|
||||
*
|
||||
* @return null if there is no ServerWorld for the given dimension
|
||||
*/
|
||||
public static ServerWorld getServerWorldFromDimension(DimensionType dimension)
|
||||
@@ -154,42 +176,43 @@ public class LodUtil
|
||||
IntegratedServer server = mc.getSingleplayerServer();
|
||||
if (server == null)
|
||||
return null;
|
||||
|
||||
|
||||
Iterable<ServerWorld> worlds = server.getAllLevels();
|
||||
ServerWorld returnWorld = null;
|
||||
|
||||
|
||||
for (ServerWorld world : worlds)
|
||||
{
|
||||
if(world.dimensionType() == dimension)
|
||||
if (world.dimensionType() == dimension)
|
||||
{
|
||||
returnWorld = world;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return returnWorld;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a 2D absolute position into a quad tree relative position.
|
||||
* Convert a 2D absolute position into a quad tree relative position.
|
||||
*/
|
||||
public static RegionPos convertGenericPosToRegionPos(int x, int z, int detailLevel)
|
||||
{
|
||||
int relativePosX = Math.floorDiv(x, (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel));
|
||||
int relativePosZ = Math.floorDiv(z, (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel));
|
||||
|
||||
|
||||
return new RegionPos(relativePosX, relativePosZ);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a 2D absolute position into a quad tree relative position.
|
||||
*/
|
||||
public static int convertLevelPos(int pos, int currectDetailLevel, int targetDetailLevel)
|
||||
{
|
||||
int newPos = Math.floorDiv(pos, (int) Math.pow(2, targetDetailLevel - currectDetailLevel));
|
||||
|
||||
|
||||
return newPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given chunk
|
||||
* has any data in it.
|
||||
@@ -197,20 +220,19 @@ public class LodUtil
|
||||
public static boolean chunkHasBlockData(IChunk chunk)
|
||||
{
|
||||
ChunkSection[] blockStorage = chunk.getSections();
|
||||
|
||||
for(ChunkSection section : blockStorage)
|
||||
|
||||
for (ChunkSection section : blockStorage)
|
||||
{
|
||||
if(section != null && !section.isEmpty())
|
||||
if (section != null && !section.isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If on single player this will return the name of the user's
|
||||
* world, if in multiplayer it will return the server name, IP,
|
||||
@@ -218,28 +240,26 @@ public class LodUtil
|
||||
*/
|
||||
public static String getWorldID(IWorld world)
|
||||
{
|
||||
if(mc.hasSingleplayerServer())
|
||||
if (mc.hasSingleplayerServer())
|
||||
{
|
||||
// chop off the dimension ID as it is not needed/wanted
|
||||
String dimId = getDimensionIDFromWorld(world);
|
||||
|
||||
|
||||
// get the world name
|
||||
int saveIndex = dimId.indexOf("saves") + 1 + "saves".length();
|
||||
int slashIndex = dimId.indexOf(File.separatorChar, saveIndex);
|
||||
dimId = dimId.substring(saveIndex, slashIndex);
|
||||
return dimId;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
return getServerId();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If on single player this will return the name of the user's
|
||||
* world and the dimensional save folder, if in multiplayer
|
||||
* world and the dimensional save folder, if in multiplayer
|
||||
* it will return the server name, ip, game version, and dimension.<br>
|
||||
* <br>
|
||||
* This can be used to determine where to save files for a given
|
||||
@@ -247,58 +267,57 @@ public class LodUtil
|
||||
*/
|
||||
public static String getDimensionIDFromWorld(IWorld world)
|
||||
{
|
||||
if(mc.hasSingleplayerServer())
|
||||
if (mc.hasSingleplayerServer())
|
||||
{
|
||||
// this will return the world save location
|
||||
// and the dimension folder
|
||||
|
||||
|
||||
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(world.dimensionType());
|
||||
if(serverWorld == null)
|
||||
if (serverWorld == null)
|
||||
throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerWorld for the dimension " + world.dimensionType().effectsLocation().getPath());
|
||||
|
||||
|
||||
ServerChunkProvider provider = serverWorld.getChunkSource();
|
||||
if(provider == null)
|
||||
if (provider == null)
|
||||
throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerChunkProvider for the dimension " + world.dimensionType().effectsLocation().getPath());
|
||||
|
||||
|
||||
return provider.dataStorage.dataFolder.toString();
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
return getServerId() + File.separatorChar + "dim_" + world.dimensionType().effectsLocation().getPath() + File.separatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the server name, IP and game version.
|
||||
*/
|
||||
public static String getServerId()
|
||||
{
|
||||
ServerData server = mc.getCurrentServer();
|
||||
|
||||
|
||||
String serverName = server.name.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverIp = server.ip.replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
String serverMcVersion = server.version.getString().replaceAll(INVALID_FILE_CHARACTERS_REGEX, "");
|
||||
|
||||
String serverId = serverName + ", IP " + serverIp + ", GameVersion " + serverMcVersion;
|
||||
|
||||
return serverId;
|
||||
|
||||
String serverId = serverName + ", IP " + serverIp + ", GameVersion " + serverMcVersion;
|
||||
|
||||
return serverId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a BlockColors int into a Color object.
|
||||
*/
|
||||
public static Color intToColor(int num)
|
||||
{
|
||||
int filter = 0b11111111;
|
||||
|
||||
int red = (num >> 16 ) & filter;
|
||||
int green = (num >> 8 ) & filter;
|
||||
|
||||
int red = (num >> 16) & filter;
|
||||
int green = (num >> 8) & filter;
|
||||
int blue = num & filter;
|
||||
|
||||
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a Color into a BlockColors object.
|
||||
*/
|
||||
@@ -306,8 +325,8 @@ public class LodUtil
|
||||
{
|
||||
return color.getRGB();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clamps the given value between the min and max values.
|
||||
* May behave strangely if min > max.
|
||||
@@ -316,7 +335,7 @@ public class LodUtil
|
||||
{
|
||||
return Math.min(max, Math.max(value, min));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clamps the given value between the min and max values.
|
||||
* May behave strangely if min > max.
|
||||
@@ -325,7 +344,7 @@ public class LodUtil
|
||||
{
|
||||
return Math.min(max, Math.max(value, min));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clamps the given value between the min and max values.
|
||||
* May behave strangely if min > max.
|
||||
@@ -337,8 +356,9 @@ public class LodUtil
|
||||
|
||||
/**
|
||||
* This methods return the number of lods that are going to be rendered in a region in the worst case
|
||||
*
|
||||
* @param regionPosX x region position to check
|
||||
* @param regionPosZ z region position to check
|
||||
* @param regionPosZ z region position to check
|
||||
* @return number of lods in the region
|
||||
*/
|
||||
public static long regionRenderingMemoryUse(int regionPosX, int regionPosZ, LodTemplate template)
|
||||
@@ -354,8 +374,8 @@ public class LodUtil
|
||||
| |
|
||||
X - X - X
|
||||
*/
|
||||
int circleCenterX = 256 + 256*xRegionSign;
|
||||
int circleCenterZ = 256 + 256*zRegionSign;
|
||||
int circleCenterX = 256 + 256 * xRegionSign;
|
||||
int circleCenterZ = 256 + 256 * zRegionSign;
|
||||
|
||||
|
||||
int innerRadius;
|
||||
@@ -366,7 +386,7 @@ public class LodUtil
|
||||
int maxDistance;
|
||||
long memoryUse = 0;
|
||||
int number = 0;
|
||||
for(byte detailLevel = BLOCK_DETAIL_LEVEL; detailLevel <= REGION_DETAIL_LEVEL; detailLevel++)
|
||||
for (byte detailLevel = BLOCK_DETAIL_LEVEL; detailLevel <= REGION_DETAIL_LEVEL; detailLevel++)
|
||||
{
|
||||
//We find now the inner and outer detail of this area
|
||||
innerRadius = DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel);
|
||||
@@ -400,59 +420,59 @@ public class LodUtil
|
||||
}
|
||||
return memoryUse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a HashSet of all ChunkPos within the normal render distance
|
||||
* that should not be rendered.
|
||||
*/
|
||||
public static HashSet<ChunkPos> getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos)
|
||||
{
|
||||
int chunkRenderDist = mc.getRenderDistance();
|
||||
ChunkPos centerChunk = new ChunkPos(playerPos);
|
||||
|
||||
// skip chunks that are already going to be rendered by Minecraft
|
||||
HashSet<ChunkPos> posToSkip = getRenderedChunks();
|
||||
|
||||
// go through each chunk within the normal view distance
|
||||
for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++)
|
||||
{
|
||||
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
|
||||
{
|
||||
if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z))
|
||||
continue;
|
||||
|
||||
long data = lodDim.getSingleData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
|
||||
|
||||
short lodAverageHeight = DataPointUtil.getHeight(data);
|
||||
|
||||
if (playerPos.getY() <= lodAverageHeight)
|
||||
{
|
||||
// don't draw Lod's that are taller than the player
|
||||
// to prevent LODs being drawn on top of the player
|
||||
posToSkip.add(new ChunkPos(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posToSkip;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns the ChunkPos of all chunks that Minecraft
|
||||
* is going to render this frame. <br><br>
|
||||
* <p>
|
||||
* Note: This isn't perfect. It will return some chunks that are outside
|
||||
* the clipping plane. (For example, if you are high above the ground some chunks
|
||||
* will be incorrectly added, even though they are outside render range).
|
||||
*/
|
||||
* Get a HashSet of all ChunkPos within the normal render distance
|
||||
* that should not be rendered.
|
||||
*/
|
||||
public static HashSet<ChunkPos> getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos)
|
||||
{
|
||||
int chunkRenderDist = mc.getRenderDistance();
|
||||
ChunkPos centerChunk = new ChunkPos(playerPos);
|
||||
|
||||
// skip chunks that are already going to be rendered by Minecraft
|
||||
HashSet<ChunkPos> posToSkip = getRenderedChunks();
|
||||
|
||||
// go through each chunk within the normal view distance
|
||||
for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++)
|
||||
{
|
||||
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
|
||||
{
|
||||
if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z))
|
||||
continue;
|
||||
|
||||
long data = lodDim.getSingleData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
|
||||
|
||||
short lodAverageHeight = DataPointUtil.getHeight(data);
|
||||
|
||||
if (playerPos.getY() <= lodAverageHeight)
|
||||
{
|
||||
// don't draw Lod's that are taller than the player
|
||||
// to prevent LODs being drawn on top of the player
|
||||
posToSkip.add(new ChunkPos(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posToSkip;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns the ChunkPos of all chunks that Minecraft
|
||||
* is going to render this frame. <br><br>
|
||||
* <p>
|
||||
* Note: This isn't perfect. It will return some chunks that are outside
|
||||
* the clipping plane. (For example, if you are high above the ground some chunks
|
||||
* will be incorrectly added, even though they are outside render range).
|
||||
*/
|
||||
public static HashSet<ChunkPos> getRenderedChunks()
|
||||
{
|
||||
HashSet<ChunkPos> loadedPos = new HashSet<>();
|
||||
|
||||
|
||||
// Wow those are some long names!
|
||||
|
||||
|
||||
// go through every RenderInfo to get the compiled chunks
|
||||
WorldRenderer renderer = mc.getLevelRenderer();
|
||||
for (WorldRenderer.LocalRenderInformationContainer worldrenderer$localrenderinformationcontainer : renderer.renderChunks)
|
||||
@@ -462,14 +482,42 @@ public class LodUtil
|
||||
{
|
||||
// add the ChunkPos for every rendered chunk
|
||||
BlockPos bpos = worldrenderer$localrenderinformationcontainer.chunk.getOrigin();
|
||||
|
||||
|
||||
loadedPos.add(new ChunkPos(bpos));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return loadedPos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static boolean isBorderChunk(boolean[][] vanillaRenderedChunks, int x, int z)
|
||||
{
|
||||
if (x < 0 || z < 0 || x >= vanillaRenderedChunks.length || z >= vanillaRenderedChunks[0].length)
|
||||
return false;
|
||||
int tempX;
|
||||
int tempZ;
|
||||
for (Direction direction : Box.ADJ_DIRECTIONS)
|
||||
{
|
||||
tempX = x + direction.getNormal().getX();
|
||||
tempZ = z + direction.getNormal().getZ();
|
||||
if (!(tempX < 0 || tempZ < 0 || tempX >= vanillaRenderedChunks.length || tempZ >= vanillaRenderedChunks[0].length))
|
||||
{
|
||||
if (!vanillaRenderedChunks[tempX][tempZ])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}else
|
||||
{
|
||||
if (vanillaRenderedChunks[x][z])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user