Compare commits

...

13 Commits

Author SHA1 Message Date
cola98765 1860729256 made this wokin with latest 1.16.5 2021-12-07 13:51:54 +01:00
cola98765 d0b0fae54e fix to that merge 2021-12-07 13:32:06 +01:00
Morippi 7786e1fea6 Change Box to VertexOptimizer and added the DataFormat folder with empty classes 2021-12-07 13:28:38 +01:00
cola98765 e5ad718ed0 fix LOWEST HorizontalQuality 2021-12-07 13:12:35 +01:00
cola98765 bda34d0a6d reverted DrawResolutionOffset 2021-12-07 13:12:22 +01:00
cola98765 2584afbd05 HorizontalScale is now a number 2-32 2021-12-07 13:12:14 +01:00
cola98765 72e4b520db updated DYNAMIC VanillaOverdraw setting. 2021-12-07 13:12:09 +01:00
cola98765 3220ad0f7a added DrawResolutionOffset to work with DrawResolution 2021-12-07 13:12:05 +01:00
James Seibel aba99f8210 Fix a few buffer building issues 2021-12-07 13:11:54 +01:00
Morippi 430579be28 Changed how data from the level container are passed as output. Removed the Thread system 2021-12-07 11:56:13 +01:00
cola98765 30cc294a04 reworked it back to primitive arrays 2021-12-04 14:03:01 +01:00
cola98765 aa79d5b5d4 small fix 2021-12-03 13:37:36 +01:00
cola98765 509ae5aba0 added new DataPoint. predicting is broken, and there are still couple errors in logs 2021-12-03 12:39:01 +01:00
24 changed files with 1083 additions and 724 deletions
@@ -23,14 +23,12 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.builders.worldGeneration.LodGenWorker;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.render.GLProxy;
import com.seibel.lod.core.render.LodRenderer;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.util.ThreadMapUtil;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
@@ -76,7 +74,7 @@ public class ClientApi
public void renderLods(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks)
{
// comment out when creating a release
// applyConfigOverrides();
applyConfigOverrides();
// clear any out of date objects
MC.clearFrameObjectCache();
@@ -148,7 +146,8 @@ public class ClientApi
configOverrideReminderPrinted = true;
}
// CONFIG.client().worldGenerator().setDistanceGenerationMode(DistanceGenerationMode.SURFACE);
// CONFIG.client().worldGenerator().setDistanceGenerationMode(DistanceGenerationMode.FULL);
// CONFIG.client().worldGenerator().setGenerationPriority(GenerationPriority.AUTO);
// CONFIG.client().graphics().advancedGraphics().setGpuUploadMethod(GpuUploadMethod.BUFFER_STORAGE);
@@ -180,14 +179,6 @@ public class ClientApi
firstTimeSetupComplete = true;
}
/** this method reset some static data every time we change world */
private void resetMod()
{
// TODO when should this be used?
ThreadMapUtil.clearMaps();
LodGenWorker.restartExecutorService();
}
@@ -21,6 +21,7 @@ package com.seibel.lod.core.api;
import org.lwjgl.glfw.GLFW;
import com.seibel.lod.core.builders.worldGeneration.LodGenWorker;
import com.seibel.lod.core.builders.worldGeneration.LodWorldGenerator;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.objects.lod.LodDimension;
@@ -115,13 +116,30 @@ public class EventApi
ClientApi.renderer.regenerateLODsNextFrame();
}
/** This is also called when the user disconnects from a server+ */
public void worldUnloadEvent()
{
// the player just unloaded a world/dimension
ThreadMapUtil.clearMaps();
new Thread(() -> checkIfDisconnectedFromServer()).start();
}
private void checkIfDisconnectedFromServer()
{
try
{
// world unloading events are called before disconnecting from the server,
// so we need to wait a second for MC to disconnect
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// this should never happen, but just in case
e.printStackTrace();
}
if (MC.getWrappedClientWorld() == null)
if (MC.getWrappedClientWorld() == null || (!MC.connectedToServer() && !MC.hasSinglePlayerServer()))
{
// the player just left the server
@@ -129,15 +147,14 @@ public class EventApi
// if this isn't done unfinished tasks may be left in the queue
// preventing new LodChunks form being generated
//LodNodeGenWorker.restartExecutorService(); // TODO why was this commented out? -James
//ThreadMapUtil.clearMaps();
LodGenWorker.restartExecutorService();
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
ApiShared.lodWorld.deselectWorld();
// prevent issues related to the buffer builder
// breaking when changing worlds.
// breaking or retaining previous data when changing worlds.
ClientApi.renderer.destroyBuffers();
recalculateWidths = true;
ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory);
@@ -30,6 +30,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import com.seibel.lod.core.objects.VertexOptimizer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
@@ -41,8 +42,8 @@ import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.enums.config.VanillaOverdraw;
import com.seibel.lod.core.enums.rendering.GLProxyContext;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.PosToRenderContainer;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.lod.LodRegion;
import com.seibel.lod.core.objects.lod.RegionPos;
@@ -142,7 +143,7 @@ public class LodBufferBuilderFactory
/** this is used to prevent multiple threads creating, destroying, or using the buffers at the same time */
private final ReentrantLock bufferLock = new ReentrantLock();
private volatile Box[][] boxCache;
private volatile VertexOptimizer[][] vertexOptimizerCache;
private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center;
@@ -184,6 +185,10 @@ public class LodBufferBuilderFactory
// setupBuffers hasn't been called yet
return;
if (MC.getCurrentLightMap() == null)
// the lighting hasn't loaded yet
return;
generatingBuffers = true;
@@ -224,11 +229,11 @@ public class LodBufferBuilderFactory
if (setsToRender.length != lodDim.getWidth())
setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()];
if (boxCache == null)
boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()];
if (vertexOptimizerCache == null)
vertexOptimizerCache = new VertexOptimizer[lodDim.getWidth()][lodDim.getWidth()];
if (boxCache.length != lodDim.getWidth())
boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()];
if (vertexOptimizerCache.length != lodDim.getWidth())
vertexOptimizerCache = new VertexOptimizer[lodDim.getWidth()][lodDim.getWidth()];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
@@ -260,7 +265,10 @@ public class LodBufferBuilderFactory
// make sure the buffers weren't
// changed while we were running this method
if (currentBuffers == null || !currentBuffers[0].building())
{
ClientApi.LOGGER.info("Buffer building quit early");
return;
}
byte minDetail = region.getMinDetailLevel();
@@ -280,14 +288,16 @@ public class LodBufferBuilderFactory
int bufferIndex;
boolean posNotInPlayerChunk;
boolean adjPosInPlayerChunk;
Box box = ThreadMapUtil.getBox();
VertexOptimizer vertexOptimizer = ThreadMapUtil.getBox();
boolean[] adjShadeDisabled = ThreadMapUtil.getAdjShadeDisabledArray();
// determine how many LODs we can stack vertically
int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte) 0);
//we get or create the map that will contain the adj data
Map<LodDirection, long[]> adjData = ThreadMapUtil.getAdjDataArray(maxVerticalData);
Map<LodDirection, int[]> adjData = ThreadMapUtil.getAdjDataArray(maxVerticalData);
Map<LodDirection, byte[]> adjFlags = ThreadMapUtil.getAdjFlagsArray(maxVerticalData);
//previous setToRender cache
if (setsToRender[xR][zR] == null)
@@ -342,12 +352,14 @@ public class LodBufferBuilderFactory
Arrays.fill(adjShadeDisabled, false);
//We check every adj block in each direction
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS)
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
{
xAdj = posX + Box.DIRECTION_NORMAL_MAP.get(lodDirection).x;
zAdj = posZ + Box.DIRECTION_NORMAL_MAP.get(lodDirection).z;
long data;
xAdj = posX + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).x;
zAdj = posZ + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).z;
int color;
int data;
byte flags;
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.getX();
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.getZ();
adjPosInPlayerChunk = (chunkXdist == 0 && chunkZdist == 0);
@@ -364,21 +376,25 @@ public class LodBufferBuilderFactory
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++)
{
data = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex);
adjShadeDisabled[Box.DIRECTION_INDEX.get(lodDirection)] = false;
flags = lodDim.getFlags(detailLevel, xAdj, zAdj, verticalIndex);
adjShadeDisabled[VertexOptimizer.DIRECTION_INDEX.get(lodDirection)] = false;
adjData.get(lodDirection)[verticalIndex] = data;
adjFlags.get(lodDirection)[verticalIndex] = flags;
}
}
else
{
//Otherwise, we check if this position is
data = lodDim.getSingleData(detailLevel, xAdj, zAdj);
data = lodDim.getData(detailLevel, xAdj, zAdj, 0);
flags = lodDim.getFlags(detailLevel, xAdj, zAdj, 0);
adjData.get(lodDirection)[0] = DataPointUtil.EMPTY_DATA;
adjData.get(lodDirection)[0] = 0;
adjFlags.get(lodDirection)[0] = 0;
if ((isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance) || (posNotInPlayerChunk && adjPosInPlayerChunk))
&& !DataPointUtil.isVoid(data))
&& DataPointUtil.doesItExist(flags) && !DataPointUtil.isVoid(flags))
{
adjShadeDisabled[Box.DIRECTION_INDEX.get(lodDirection)] = DataPointUtil.getAlpha(data) < 255;
adjShadeDisabled[VertexOptimizer.DIRECTION_INDEX.get(lodDirection)] = DataPointUtil.getAlpha(data) < 255;
}
}
}
@@ -386,42 +402,55 @@ public class LodBufferBuilderFactory
// We render every vertical lod present in this position
// We only stop when we find a block that is void or non-existing block
long data;
int color;
int data;
byte flags;
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++)
{
//we get the above block as adj UP
if (verticalIndex > 0)
{
adjData.get(LodDirection.UP)[0] = lodDim.getData(detailLevel, posX, posZ, verticalIndex - 1);
adjFlags.get(LodDirection.UP)[0] = lodDim.getFlags(detailLevel, posX, posZ, verticalIndex - 1);
}
else
adjData.get(LodDirection.UP)[0] = DataPointUtil.EMPTY_DATA;
{
adjData.get(LodDirection.UP)[0] = 0;
adjFlags.get(LodDirection.UP)[0] = 0;
}
//we get the below block as adj DOWN
if (verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ) - 1)
{
adjData.get(LodDirection.DOWN)[0] = lodDim.getData(detailLevel, posX, posZ, verticalIndex + 1);
adjFlags.get(LodDirection.DOWN)[0] = lodDim.getFlags(detailLevel, posX, posZ, verticalIndex + 1);
}
else
adjData.get(LodDirection.DOWN)[0] = DataPointUtil.EMPTY_DATA;
{
adjData.get(LodDirection.DOWN)[0] = 0;
adjFlags.get(LodDirection.DOWN)[0] = 0;
}
//We extract the data to render
color = lodDim.getColor(detailLevel, posX, posZ, verticalIndex);
data = lodDim.getData(detailLevel, posX, posZ, verticalIndex);
flags = lodDim.getFlags(detailLevel, posX, posZ, verticalIndex);
//If the data is not renderable (Void or non-existing) we stop since there is no data left in this position
if (DataPointUtil.isVoid(data) || !DataPointUtil.doesItExist(data))
if (!DataPointUtil.doesItExist(flags) || DataPointUtil.isVoid(flags))
break;
//We send the call to create the vertices
CONFIG.client().graphics().advancedGraphics().getLodTemplate().template.addLodToBuffer(currentBuffers[bufferIndex], playerBlockPosRounded, data, adjData,
detailLevel, posX, posZ, box, renderer.previousDebugMode, adjShadeDisabled);
CONFIG.client().graphics().advancedGraphics().getLodTemplate().template.addLodToBuffer(currentBuffers[bufferIndex], playerBlockPosRounded, color, data, flags, adjData, adjFlags,
detailLevel, posX, posZ, vertexOptimizer, renderer.previousDebugMode, adjShadeDisabled);
}
} // for pos to in list to render
// the thread executed successfully
return true;
};
nodeToRenderThreads.add(dataToRenderThread);
}
} // region z
} // region z
@@ -459,12 +488,12 @@ public class LodBufferBuilderFactory
}
finally
{
// clean up any potentially open resources
if (buildableBuffers != null)
closeBuffers(fullRegen, lodDim);
try
{
// clean up any potentially open resources
if (buildableBuffers != null)
closeBuffers(fullRegen, lodDim);
// upload the new buffers
uploadBuffers(fullRegen, lodDim);
}
@@ -524,108 +553,120 @@ public class LodBufferBuilderFactory
*/
public void setupBuffers(LodDimension lodDimension)
{
bufferLock.lock();
int numbRegionsWide = lodDimension.getWidth();
long regionMemoryRequired;
int numberOfBuffers;
GLProxy glProxy = GLProxy.getInstance();
GLProxyContext oldContext = glProxy.getGlContext();
glProxy.setGlContext(GLProxyContext.LOD_BUILDER);
previousRegionWidth = numbRegionsWide;
numberOfBuffersPerRegion = new int[numbRegionsWide][numbRegionsWide];
buildableBuffers = new LodBufferBuilder[numbRegionsWide][numbRegionsWide][];
buildableVbos = new LodVertexBuffer[numbRegionsWide][numbRegionsWide][];
drawableVbos = new LodVertexBuffer[numbRegionsWide][numbRegionsWide][];
if (glProxy.bufferStorageSupported)
try
{
buildableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide][];
drawableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide][];
}
bufferLock.lock();
for (int x = 0; x < numbRegionsWide; x++)
{
for (int z = 0; z < numbRegionsWide; z++)
int numbRegionsWide = lodDimension.getWidth();
long regionMemoryRequired;
int numberOfBuffers;
GLProxy glProxy = GLProxy.getInstance();
GLProxyContext oldContext = glProxy.getGlContext();
glProxy.setGlContext(GLProxyContext.LOD_BUILDER);
previousRegionWidth = numbRegionsWide;
numberOfBuffersPerRegion = new int[numbRegionsWide][numbRegionsWide];
buildableBuffers = new LodBufferBuilder[numbRegionsWide][numbRegionsWide][];
buildableVbos = new LodVertexBuffer[numbRegionsWide][numbRegionsWide][];
drawableVbos = new LodVertexBuffer[numbRegionsWide][numbRegionsWide][];
if (glProxy.bufferStorageSupported)
{
regionMemoryRequired = DEFAULT_MEMORY_ALLOCATION;
buildableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide][];
drawableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide][];
}
// if the memory required is greater than the max buffer
// capacity, divide the memory across multiple buffers
if (regionMemoryRequired > LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY)
for (int x = 0; x < numbRegionsWide; x++)
{
for (int z = 0; z < numbRegionsWide; z++)
{
numberOfBuffers = (int) regionMemoryRequired / LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY + 1;
regionMemoryRequired = DEFAULT_MEMORY_ALLOCATION;
// TODO shouldn't this be determined with regionMemoryRequired?
// always allocating the max memory is a bit expensive isn't it?
regionMemoryRequired = LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY;
numberOfBuffersPerRegion[x][z] = numberOfBuffers;
buildableBuffers[x][z] = new LodBufferBuilder[numberOfBuffers];
buildableVbos[x][z] = new LodVertexBuffer[numberOfBuffers];
drawableVbos[x][z] = new LodVertexBuffer[numberOfBuffers];
if (glProxy.bufferStorageSupported)
// if the memory required is greater than the max buffer
// capacity, divide the memory across multiple buffers
if (regionMemoryRequired > LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY)
{
buildableStorageBufferIds[x][z] = new int[numberOfBuffers];
drawableStorageBufferIds[x][z] = new int[numberOfBuffers];
numberOfBuffers = (int) regionMemoryRequired / LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY + 1;
// TODO shouldn't this be determined with regionMemoryRequired?
// always allocating the max memory is a bit expensive isn't it?
regionMemoryRequired = LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY;
numberOfBuffersPerRegion[x][z] = numberOfBuffers;
buildableBuffers[x][z] = new LodBufferBuilder[numberOfBuffers];
buildableVbos[x][z] = new LodVertexBuffer[numberOfBuffers];
drawableVbos[x][z] = new LodVertexBuffer[numberOfBuffers];
if (glProxy.bufferStorageSupported)
{
buildableStorageBufferIds[x][z] = new int[numberOfBuffers];
drawableStorageBufferIds[x][z] = new int[numberOfBuffers];
}
}
}
else
{
// we only need one buffer for this region
numberOfBuffersPerRegion[x][z] = 1;
buildableBuffers[x][z] = new LodBufferBuilder[1];
buildableVbos[x][z] = new LodVertexBuffer[1];
drawableVbos[x][z] = new LodVertexBuffer[1];
if (glProxy.bufferStorageSupported)
else
{
buildableStorageBufferIds[x][z] = new int[1];
drawableStorageBufferIds[x][z] = new int[1];
// we only need one buffer for this region
numberOfBuffersPerRegion[x][z] = 1;
buildableBuffers[x][z] = new LodBufferBuilder[1];
buildableVbos[x][z] = new LodVertexBuffer[1];
drawableVbos[x][z] = new LodVertexBuffer[1];
if (glProxy.bufferStorageSupported)
{
buildableStorageBufferIds[x][z] = new int[1];
drawableStorageBufferIds[x][z] = new int[1];
}
}
}
for (int i = 0; i < numberOfBuffersPerRegion[x][z]; i++)
{
buildableBuffers[x][z][i] = new LodBufferBuilder((int) regionMemoryRequired);
buildableVbos[x][z][i] = new LodVertexBuffer();
drawableVbos[x][z][i] = new LodVertexBuffer();
// create the initial mapped buffers (system memory)
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableVbos[x][z][i].id);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableVbos[x][z][i].id);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
if (glProxy.bufferStorageSupported)
for (int i = 0; i < numberOfBuffersPerRegion[x][z]; i++)
{
// create the buffer storage (GPU memory)
buildableStorageBufferIds[x][z][i] = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableStorageBufferIds[x][z][i]);
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); // the 0 flag means to create the storage in the GPUs memory
buildableBuffers[x][z][i] = new LodBufferBuilder((int) regionMemoryRequired);
buildableVbos[x][z][i] = new LodVertexBuffer();
drawableVbos[x][z][i] = new LodVertexBuffer();
// create the initial mapped buffers (system memory)
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableVbos[x][z][i].id);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
drawableStorageBufferIds[x][z][i] = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableStorageBufferIds[x][z][i]);
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableVbos[x][z][i].id);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
if (glProxy.bufferStorageSupported)
{
// create the buffer storage (GPU memory)
buildableStorageBufferIds[x][z][i] = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableStorageBufferIds[x][z][i]);
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); // the 0 flag means to create the storage in the GPUs memory
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
drawableStorageBufferIds[x][z][i] = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableStorageBufferIds[x][z][i]);
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
}
}
}
}
glProxy.setGlContext(oldContext);
bufferLock.unlock();
glProxy.setGlContext(oldContext);
}
catch (Exception e)
{
ClientApi.LOGGER.info("setupBuffers ran into trouble: " + e.getMessage(), e);
}
finally
{
// this shouldn't normally happen, but just in case it sill prevent deadlock
bufferLock.unlock();
}
}
@@ -638,85 +679,95 @@ public class LodBufferBuilderFactory
*/
public void destroyBuffers()
{
bufferLock.lock();
// destroy the buffer storages if they aren't already
if (buildableStorageBufferIds != null)
try
{
for (int x = 0; x < buildableStorageBufferIds.length; x++)
bufferLock.lock();
// destroy the buffer storages if they aren't already
if (buildableStorageBufferIds != null)
{
for (int z = 0; z < buildableStorageBufferIds.length; z++)
for (int x = 0; x < buildableStorageBufferIds.length; x++)
{
for (int i = 0; i < buildableStorageBufferIds[x][z].length; i++)
for (int z = 0; z < buildableStorageBufferIds.length; z++)
{
int buildableId = buildableStorageBufferIds[x][z][i];
int drawableId = drawableStorageBufferIds[x][z][i];
// make sure the buffers are deleted in a openGL context
GLProxy.getInstance().recordOpenGlCall(() ->
for (int i = 0; i < buildableStorageBufferIds[x][z].length; i++)
{
GL15.glDeleteBuffers(buildableId);
GL15.glDeleteBuffers(drawableId);
});
}
}
}
}
int buildableId = buildableStorageBufferIds[x][z][i];
int drawableId = drawableStorageBufferIds[x][z][i];
buildableStorageBufferIds = null;
drawableStorageBufferIds = null;
// destroy the VBOs if they aren't already
if (buildableVbos != null)
{
for (int i = 0; i < buildableVbos.length; i++)
{
for (int j = 0; j < buildableVbos.length; j++)
{
for (int k = 0; k < buildableVbos[i][j].length; k++)
{
int buildableId;
int drawableId;
// variables passed into a lambda expression
// need to be effectively final, so we have
// to use an else statement here
if (buildableVbos[i][j][k] != null)
buildableId = buildableVbos[i][j][k].id;
else
buildableId = 0;
if (drawableVbos[i][j][k] != null)
drawableId = drawableVbos[i][j][k].id;
else
drawableId = 0;
GLProxy.getInstance().recordOpenGlCall(() ->
{
if (buildableId != 0)
// make sure the buffers are deleted in a openGL context
GLProxy.getInstance().recordOpenGlCall(() ->
{
GL15.glDeleteBuffers(buildableId);
if (drawableId != 0)
GL15.glDeleteBuffers(drawableId);
});
});
}
}
}
}
buildableStorageBufferIds = null;
drawableStorageBufferIds = null;
// destroy the VBOs if they aren't already
if (buildableVbos != null)
{
for (int i = 0; i < buildableVbos.length; i++)
{
for (int j = 0; j < buildableVbos.length; j++)
{
for (int k = 0; k < buildableVbos[i][j].length; k++)
{
int buildableId;
int drawableId;
// variables passed into a lambda expression
// need to be effectively final, so we have
// to use an else statement here
if (buildableVbos[i][j][k] != null)
buildableId = buildableVbos[i][j][k].id;
else
buildableId = 0;
if (drawableVbos[i][j][k] != null)
drawableId = drawableVbos[i][j][k].id;
else
drawableId = 0;
GLProxy.getInstance().recordOpenGlCall(() ->
{
if (buildableId != 0)
GL15.glDeleteBuffers(buildableId);
if (drawableId != 0)
GL15.glDeleteBuffers(drawableId);
});
}
}
}
}
buildableVbos = null;
drawableVbos = null;
// these don't contain any OpenGL objects, so
// they don't require any special clean-up
buildableBuffers = null;
}
catch (Exception e)
{
ClientApi.LOGGER.info("destroyBuffers ran into trouble: " + e.getMessage(), e);
}
finally
{
// this shouldn't normally happen, but just in case it sill prevent deadlock
bufferLock.unlock();
}
buildableVbos = null;
drawableVbos = null;
// these don't contain any OpenGL objects, so
// they don't require any special clean-up
buildableBuffers = null;
bufferLock.unlock();
}
/** Calls begin on each of the buildable BufferBuilders. */
@@ -977,19 +1028,30 @@ public class LodBufferBuilderFactory
// since this is called on the main render thread
if (bufferLock.tryLock())
{
LodVertexBuffer[][][] tmpVbo = drawableVbos;
drawableVbos = buildableVbos;
buildableVbos = tmpVbo;
try
{
LodVertexBuffer[][][] tmpVbo = drawableVbos;
drawableVbos = buildableVbos;
buildableVbos = tmpVbo;
int[][][] tmpStorage = drawableStorageBufferIds;
drawableStorageBufferIds = buildableStorageBufferIds;
buildableStorageBufferIds = tmpStorage;
int[][][] tmpStorage = drawableStorageBufferIds;
drawableStorageBufferIds = buildableStorageBufferIds;
buildableStorageBufferIds = tmpStorage;
drawableCenterChunkPos = buildableCenterChunkPos;
drawableCenterChunkPos = buildableCenterChunkPos;
// the vbos have been swapped
switchVbos = false;
bufferLock.unlock();
// the vbos have been swapped
switchVbos = false;
}
catch (Exception e)
{
// this shouldn't normally happen, but just in case it sill prevent deadlock
ClientApi.LOGGER.info("getVertexBuffers ran into trouble: " + e.getMessage(), e);
}
finally
{
bufferLock.unlock();
}
}
return new VertexBuffersAndOffset(drawableVbos, drawableStorageBufferIds, drawableCenterChunkPos);
@@ -23,7 +23,7 @@ import java.util.Map;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
@@ -37,8 +37,8 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public abstract class AbstractLodTemplate
{
/** Uploads the given LOD to the buffer. */
public abstract void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled);
public abstract void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags, Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled);
/** add the given position and color to the buffer */
protected void addPosAndColor(LodBufferBuilder buffer,
@@ -23,7 +23,7 @@ import java.util.Map;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil;
@@ -44,43 +44,43 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
@Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled)
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos,
int color, int data, byte flags,
Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
if (box == null)
if (vertexOptimizer == null)
return;
// equivalent to 2^detailLevel
int blockWidth = 1 << detailLevel;
int color;
if (debugging != DebugMode.OFF)
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
else
color = DataPointUtil.getColor(data);
generateBoundingBox(
box,
vertexOptimizer,
DataPointUtil.getHeight(data),
DataPointUtil.getDepth(data),
blockWidth,
posX * blockWidth, 0, posZ * blockWidth, // x, y, z offset
bufferCenterBlockPos,
adjData,
adjFlags,
color,
DataPointUtil.getLightSkyAlt(data),
DataPointUtil.getLightSkyAlt(data, flags),
DataPointUtil.getLightBlock(data),
adjShadeDisabled);
addBoundingBoxToBuffer(buffer, box);
addBoundingBoxToBuffer(buffer, vertexOptimizer);
}
private void generateBoundingBox(Box box,
private void generateBoundingBox(VertexOptimizer vertexOptimizer,
int height, int depth, int width,
double xOffset, double yOffset, double zOffset,
AbstractBlockPosWrapper bufferCenterBlockPos,
Map<LodDirection, long[]> adjData,
Map<LodDirection, int[]> adjData,
Map<LodDirection, byte[]> adjFlags,
int color,
int skyLight,
int blockLight,
@@ -100,38 +100,38 @@ public class CubicLodTemplate extends AbstractLodTemplate
// which only uses floats
double x = -bufferCenterBlockPos.getX();
double z = -bufferCenterBlockPos.getZ();
box.reset();
box.setColor(color, adjShadeDisabled);
box.setLights(skyLight, blockLight);
box.setWidth(width, height - depth, width);
box.setOffset((int) (xOffset + x), (int) (depth + yOffset), (int) (zOffset + z));
box.setUpCulling(32, bufferCenterBlockPos);
box.setAdjData(adjData);
vertexOptimizer.reset();
vertexOptimizer.setColor(color, adjShadeDisabled);
vertexOptimizer.setLights(skyLight, blockLight);
vertexOptimizer.setWidth(width, height - depth, width);
vertexOptimizer.setOffset((int) (xOffset + x), (int) (depth + yOffset), (int) (zOffset + z));
vertexOptimizer.setUpCulling(32, bufferCenterBlockPos);
vertexOptimizer.setAdjData(adjData, adjFlags);
}
private void addBoundingBoxToBuffer(LodBufferBuilder buffer, Box box)
private void addBoundingBoxToBuffer(LodBufferBuilder buffer, VertexOptimizer vertexOptimizer)
{
int color;
int skyLight;
int blockLight;
for (LodDirection lodDirection : Box.DIRECTIONS)
for (LodDirection lodDirection : VertexOptimizer.DIRECTIONS)
{
if(box.isCulled(lodDirection))
if(vertexOptimizer.isCulled(lodDirection))
continue;
int verticalFaceIndex = 0;
while (box.shouldRenderFace(lodDirection, verticalFaceIndex))
while (vertexOptimizer.shouldRenderFace(lodDirection, verticalFaceIndex))
{
for (int vertexIndex = 0; vertexIndex < 6; vertexIndex++)
{
color = box.getColor(lodDirection);
skyLight = box.getSkyLight(lodDirection, verticalFaceIndex);
blockLight = box.getBlockLight();
color = vertexOptimizer.getColor(lodDirection);
skyLight = vertexOptimizer.getSkyLight(lodDirection, verticalFaceIndex);
blockLight = vertexOptimizer.getBlockLight();
color = ColorUtil.applyLightValue(color, skyLight, blockLight);
addPosAndColor(buffer,
box.getX(lodDirection, vertexIndex),
box.getY(lodDirection, vertexIndex, verticalFaceIndex) + DataPointUtil.VERTICAL_OFFSET,
box.getZ(lodDirection, vertexIndex),
vertexOptimizer.getX(lodDirection, vertexIndex),
vertexOptimizer.getY(lodDirection, vertexIndex, verticalFaceIndex) + DataPointUtil.VERTICAL_OFFSET,
vertexOptimizer.getZ(lodDirection, vertexIndex),
color);
}
verticalFaceIndex++;
@@ -24,7 +24,7 @@ import java.util.Map;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
@@ -39,8 +39,9 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public class DynamicLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled)
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags,
Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
}
@@ -24,7 +24,7 @@ import java.util.Map;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
@@ -37,8 +37,9 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public class TriangularLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled)
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags,
Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
}
@@ -195,105 +195,107 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
startX = detail.startX[i];
startZ = detail.startZ[i];
long[] data;
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
// creates a vertical DataPoint
// equivalent to 2^detailLevel
int size = 1 << detail.detailLevel;
int[] dataToMergeColor = ThreadMapUtil.getBuilderVerticalArrayColor(detail.detailLevel);
int[] dataToMergeData = ThreadMapUtil.getBuilderVerticalArrayData(detail.detailLevel);
byte[] dataToMergeFlags = ThreadMapUtil.getBuilderVerticalArrayFlags(detail.detailLevel);
int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
AbstractChunkPosWrapper chunkPos = chunk.getPos();
int height;
int depth;
int color;
int light;
int lightSky;
int lightBlock;
byte generation = config.distanceGenerationMode.complexity;
int xRel;
int zRel;
int xAbs;
int yAbs;
int zAbs;
boolean hasCeiling = MC.getWrappedClientWorld().getDimensionType().hasCeiling();
boolean hasSkyLight = MC.getWrappedClientWorld().getDimensionType().hasSkyLight();
boolean isDefault;
AbstractBlockPosWrapper blockPos = FACTORY.createBlockPos();
int index;
for (index = 0; index < size * size; index++)
{
xRel = startX + index % size;
zRel = startZ + index / size;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
//Calculate the height of the lod
yAbs = DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET + 1;
int count = 0;
boolean topBlock = true;
while (yAbs > 0)
{
height = determineHeightPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
// If the lod is at the default height, it must be void data
if (height == DEFAULT_HEIGHT)
{
if (topBlock)
dataToMergeFlags[index * verticalData] = DataPointUtil.createVoidDataPoint(generation);
break;
}
yAbs = height - 1;
// We search light on above air block
depth = determineBottomPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
if (hasCeiling && topBlock)
{
yAbs = depth;
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, true, hasSkyLight, true);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs, blockPos);
blockPos.set(xAbs, yAbs - 1, zAbs);
}
else
{
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, topBlock);
color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos);
blockPos.set(xAbs, yAbs + 1, zAbs);
}
lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111;
isDefault = ((light >> 8)) == 1;
DataPointUtil.createDataPoint(height - DataPointUtil.VERTICAL_OFFSET, depth - DataPointUtil.VERTICAL_OFFSET, color, lightSky, lightBlock, generation, isDefault);
dataToMergeColor[index * verticalData + count] = ThreadMapUtil.dataPointColor;
dataToMergeData[index * verticalData + count] = ThreadMapUtil.dataPointData;
dataToMergeFlags[index * verticalData + count] = ThreadMapUtil.dataPointFlags;
topBlock = false;
yAbs = depth - 1;
count++;
}
}
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
int[] mergedColor = ThreadMapUtil.getRawVerticalDataArrayColor();
int[] mergedData = ThreadMapUtil.getRawVerticalDataArrayData();
byte[] mergedFlags = ThreadMapUtil.getRawVerticalDataArrayFlags();
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.length != 0)
if (mergedFlags.length != 0)
{
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().getX() * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().getZ() * 16 + startZ, detail.detailLevel);
lodDim.addVerticalData(detailLevel, posX, posZ, data, false);
lodDim.addVerticalData(detailLevel, posX, posZ, mergedColor, mergedData, mergedFlags, false);
}
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().getX(), chunk.getPos().getZ());
}
/** creates a vertical DataPoint */
private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunkWrapper chunk, LodBuilderConfig config, int startX, int startZ)
{
// equivalent to 2^detailLevel
int size = 1 << detail.detailLevel;
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail.detailLevel);
int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
AbstractChunkPosWrapper chunkPos = chunk.getPos();
int height;
int depth;
int color;
int light;
int lightSky;
int lightBlock;
int generation = config.distanceGenerationMode.complexity;
int xRel;
int zRel;
int xAbs;
int yAbs;
int zAbs;
boolean hasCeiling = MC.getWrappedClientWorld().getDimensionType().hasCeiling();
boolean hasSkyLight = MC.getWrappedClientWorld().getDimensionType().hasSkyLight();
boolean isDefault;
AbstractBlockPosWrapper blockPos = FACTORY.createBlockPos();
int index;
for (index = 0; index < size * size; index++)
{
xRel = startX + index % size;
zRel = startZ + index / size;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
//Calculate the height of the lod
yAbs = DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET + 1;
int count = 0;
boolean topBlock = true;
while (yAbs > 0)
{
height = determineHeightPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
// If the lod is at the default height, it must be void data
if (height == DEFAULT_HEIGHT)
{
if (topBlock)
dataToMerge[index * verticalData] = DataPointUtil.createVoidDataPoint(generation);
break;
}
yAbs = height - 1;
// We search light on above air block
depth = determineBottomPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
if (hasCeiling && topBlock)
{
yAbs = depth;
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, true, hasSkyLight, true);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs, blockPos);
blockPos.set(xAbs, yAbs - 1, zAbs);
}
else
{
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, topBlock);
color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos);
blockPos.set(xAbs, yAbs + 1, zAbs);
}
lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111;
isDefault = ((light >> 8)) == 1;
dataToMerge[index * verticalData + count] = DataPointUtil.createDataPoint(height - DataPointUtil.VERTICAL_OFFSET, depth - DataPointUtil.VERTICAL_OFFSET, color, lightSky, lightBlock, generation, isDefault);
topBlock = false;
yAbs = depth - 1;
count++;
}
}
return dataToMerge;
}
/**
* Find the lowest valid point from the bottom.
* Used when creating a vertical LOD.
@@ -0,0 +1,5 @@
package com.seibel.lod.core.dataFormat;
public class BlockDataFormat
{
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.dataFormat;
public class ColorFormat
{
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.dataFormat;
public class DepthHeightFormat
{
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.dataFormat;
public class LightFormat
{
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.dataFormat;
public class PositionDataFormat
{
}
@@ -21,7 +21,6 @@ package com.seibel.lod.core.handlers;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
@@ -78,7 +77,7 @@ public class LodDimensionFileHandler
* file handler, older versions (smaller numbers) will be deleted and overwritten,
* newer versions (larger numbers) will be ignored and won't be read.
*/
public static final int LOD_SAVE_FILE_VERSION = 7;
public static final int LOD_SAVE_FILE_VERSION = 8;
/**
* Allow saving asynchronously, but never try to save multiple regions
@@ -208,14 +207,14 @@ public class LodDimensionFileHandler
break;
}
else if (fileVersion == 6)
else if (fileVersion < LOD_SAVE_FILE_VERSION)
{
//this is old, but readable version
byte[] data = ThreadMapUtil.getSaveContainer(tempDetailLevel);
inputStream.read(data);
inputStream.close();
// add the data to our region
region.addLevelContainer(new VerticalLevelContainer(data, 6));
region.addLevelContainer(new VerticalLevelContainer(data, fileVersion));
} else
{
// this file is a readable version,
@@ -35,12 +35,11 @@ import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
/**
* Similar to Minecraft's AxisAlignedBoundingBox.
*
* This class handles all the vertex optimization that's needed for a column of lods. W
* @author Leonardo Amato
* @version 10-2-2021
*/
public class Box
public class VertexOptimizer
{
private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class);
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
@@ -207,7 +206,7 @@ public class Box
/** creates an empty box */
@SuppressWarnings("serial")
public Box()
public VertexOptimizer()
{
boxOffset = new int[3];
boxWidth = new int[3];
@@ -339,25 +338,27 @@ public class Box
* This method create all the shared face culling based on the adjacent data
* @param adjData data adjacent to the column we are going to render
*/
public void setAdjData(Map<LodDirection, long[]> adjData)
public void setAdjData(Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags)
{
int height;
int depth;
int minY = getMinY();
int maxY = getMaxY();
long singleAdjDataPoint;
int singleAdjData;
byte singleAdjFlags;
/* TODO implement attached vertical face culling
//Up direction case
if(DataPointUtil.doesItExist(adjData.get(Direction.UP)))
{
height = DataPointUtil.getHeight(singleAdjDataPoint);
depth = DataPointUtil.getDepth(singleAdjDataPoint);
height = DataPointUtil.getHeight(singleAdjData);
depth = DataPointUtil.getDepth(singleAdjData);
}*/
//Down direction case
singleAdjDataPoint = adjData.get(LodDirection.DOWN)[0];
if(DataPointUtil.doesItExist(singleAdjDataPoint))
skyLights.get(LodDirection.DOWN)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
singleAdjData = adjData.get(LodDirection.DOWN)[0];
singleAdjFlags = adjFlags.get(LodDirection.DOWN)[0];
if(DataPointUtil.doesItExist(singleAdjFlags))
skyLights.get(LodDirection.DOWN)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
else
skyLights.get(LodDirection.DOWN)[0] = skyLights.get(LodDirection.UP)[0];
//other sided
@@ -367,8 +368,9 @@ public class Box
if (isCulled(lodDirection))
continue;
long[] dataPoint = adjData.get(lodDirection);
if (dataPoint == null || DataPointUtil.isVoid(dataPoint[0]))
int[] data = adjData.get(lodDirection);
byte[] flags = adjFlags.get(lodDirection);
if (DataPointUtil.isVoid(flags[0]))
{
adjHeight.get(lodDirection)[0] = maxY;
adjDepth.get(lodDirection)[0] = minY;
@@ -384,15 +386,16 @@ public class Box
boolean toFinish = false;
int toFinishIndex = 0;
boolean allAbove = true;
for (i = 0; i < dataPoint.length; i++)
for (i = 0; i < flags.length; i++)
{
singleAdjDataPoint = dataPoint[i];
singleAdjData = data[i];
singleAdjFlags = flags[i];
if (DataPointUtil.isVoid(singleAdjDataPoint) || !DataPointUtil.doesItExist(singleAdjDataPoint))
if (DataPointUtil.isVoid(singleAdjFlags) || !DataPointUtil.doesItExist(singleAdjFlags))
break;
height = DataPointUtil.getHeight(singleAdjDataPoint);
depth = DataPointUtil.getDepth(singleAdjDataPoint);
height = DataPointUtil.getHeight(singleAdjData);
depth = DataPointUtil.getDepth(singleAdjData);
if (depth <= maxY)
{
@@ -405,12 +408,12 @@ public class Box
{
adjHeight.get(lodDirection)[0] = getMaxY();
adjDepth.get(lodDirection)[0] = getMinY();
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); //skyLights.get(Direction.UP)[0];
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags); //skyLights.get(Direction.UP)[0];
}
else
{
adjDepth.get(lodDirection)[faceToDraw] = getMinY();
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
}
faceToDraw++;
toFinish = false;
@@ -436,12 +439,12 @@ public class Box
{
adjHeight.get(lodDirection)[0] = getMaxY();
adjDepth.get(lodDirection)[0] = height;
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); //skyLights.get(Direction.UP)[0];
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags); //skyLights.get(Direction.UP)[0];
}
else
{
adjDepth.get(lodDirection)[faceToDraw] = height;
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
}
toFinish = false;
faceToDraw++;
@@ -453,7 +456,7 @@ public class Box
// the adj data intersects the higher part of the current data
// we start the creation of a new face
adjHeight.get(lodDirection)[faceToDraw] = depth;
//skyLights.get(direction)[faceToDraw] = (byte) DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
//skyLights.get(direction)[faceToDraw] = (byte) DataPointUtil.getLightSkyAlt(singleAdjData);
firstFace = false;
toFinish = true;
toFinishIndex = i + 1;
@@ -469,7 +472,7 @@ public class Box
}
adjDepth.get(lodDirection)[faceToDraw] = height;
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
faceToDraw++;
adjHeight.get(lodDirection)[faceToDraw] = depth;
firstFace = false;
@@ -489,11 +492,12 @@ public class Box
else if (toFinish)
{
adjDepth.get(lodDirection)[faceToDraw] = minY;
if(toFinishIndex < dataPoint.length)
if(toFinishIndex < flags.length)
{
singleAdjDataPoint = dataPoint[toFinishIndex];
if (DataPointUtil.doesItExist(singleAdjDataPoint))
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
singleAdjData = data[toFinishIndex];
singleAdjFlags = flags[toFinishIndex];
if (DataPointUtil.doesItExist(singleAdjFlags))
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
else
skyLights.get(lodDirection)[faceToDraw] = skyLights.get(LodDirection.UP)[0];
}
@@ -32,7 +32,7 @@ public interface LevelContainer
* @param index z position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addData(long data, int posX, int posZ, int index);
boolean addData(int color, int data, byte flags, int posX, int posZ, int index);
/**
* With this you can add data to the level container
@@ -41,7 +41,7 @@ public interface LevelContainer
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addVerticalData(long[] data, int posX, int posZ);
boolean addVerticalData(int[] color, int[] data, byte[] flags, int posX, int posZ);
/**
* With this you can add data to the level container
@@ -50,25 +50,18 @@ public interface LevelContainer
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addSingleData(long data, int posX, int posZ);
/**
* With this you can get data from the level container
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return the data in long array format
*/
long getData(int posX, int posZ, int index);
/**
* With this you can get data from the level container
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return the data in long array format
*/
long getSingleData(int posX, int posZ);
boolean addSingleData(int color, int data, byte flags, int posX, int posZ);
int getColor(int posX, int posZ, int verticalIndex);
int getData(int posX, int posZ, int index);
byte getFlags(int posX, int posZ, int index);
byte getSingleFlags(int posX, int posZ);
/**
* data is returned to ThreadMapUtil variables
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true only if the data exist
@@ -30,12 +30,7 @@ import com.seibel.lod.core.enums.config.VerticalQuality;
import com.seibel.lod.core.handlers.LodDimensionFileHandler;
import com.seibel.lod.core.objects.PosToGenerateContainer;
import com.seibel.lod.core.objects.PosToRenderContainer;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodThreadFactory;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.util.*;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
@@ -445,7 +440,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten.
*/
public Boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data, boolean dontSave)
public Boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, int color, int data, byte flags, boolean dontSave)
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -455,7 +450,7 @@ public class LodDimension
if (region == null)
return false;
boolean nodeAdded = region.addData(detailLevel, posX, posZ, verticalIndex, data);
boolean nodeAdded = region.addData(detailLevel, posX, posZ, verticalIndex, color, data, flags);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
@@ -487,7 +482,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten.
*/
public Boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data, boolean dontSave)
public Boolean addVerticalData(byte detailLevel, int posX, int posZ, int[] color, int[] data, byte[] flags, boolean dontSave)
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -497,7 +492,7 @@ public class LodDimension
if (region == null)
return false;
boolean nodeAdded = region.addVerticalData(detailLevel, posX, posZ, data);
boolean nodeAdded = region.addVerticalData(detailLevel, posX, posZ, color, data, flags);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
@@ -566,7 +561,9 @@ public class LodDimension
byte detailLevel;
int posX;
int posZ;
long data;
int color;
int data;
byte flags;
int numbChunksWide = (width) * 32;
int circleLimit = Integer.MAX_VALUE;
@@ -614,11 +611,11 @@ public class LodDimension
posX = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, detailLevel);
posZ = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, zChunkToCheck, detailLevel);
data = getSingleData(detailLevel, posX, posZ);
flags = getSingleFlags(detailLevel, posX, posZ);
//we will generate the position only if the current generation complexity is lower than the target one.
//an un-generated area will always have 0 generation
if (DataPointUtil.getGenerationMode(data) < complexity)
if (DataPointUtil.getGenerationMode(flags) < complexity)
{
posToGenerate.addPosToGenerate(detailLevel, posX, posZ);
if (maxDataToGenerate >= 0)
@@ -705,43 +702,52 @@ public class LodDimension
return region.getMaxVerticalData(detailLevel);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
* <br>
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public long getData(byte detailLevel, int posX, int posZ, int verticalIndex)
public int getColor(byte detailLevel, int posX, int posZ, int verticalIndex)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
return DataPointUtil.EMPTY_DATA;
return region.getData(detailLevel, posX, posZ, verticalIndex);
return 0;
else
return region.getColor(detailLevel, posX, posZ, verticalIndex);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
* <br>
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public long getSingleData(byte detailLevel, int posX, int posZ)
public int getData(byte detailLevel, int posX, int posZ, int verticalIndex)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
return DataPointUtil.EMPTY_DATA;
return 0;
else
return region.getData(detailLevel, posX, posZ, verticalIndex);
}
return region.getSingleData(detailLevel, posX, posZ);
public byte getFlags(byte detailLevel, int posX, int posZ, int verticalIndex)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
return 0;
else
return region.getFlags(detailLevel, posX, posZ, verticalIndex);
}
public byte getSingleFlags(byte detailLevel, int posX, int posZ)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
return (byte) 0;
else
return region.getSingleFlags(detailLevel, posX, posZ);
}
/** Clears the given region */
@@ -154,7 +154,7 @@ public class LodRegion
* TODO this will always return true unless it has
* @return true if the data was added successfully
*/
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data)
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, int color, int data, byte flags)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
@@ -166,7 +166,7 @@ public class LodRegion
this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
}
this.dataContainer[detailLevel].addData(data, posX, posZ, verticalIndex);
this.dataContainer[detailLevel].addData(color, data, flags, posX, posZ, verticalIndex);
return true;
}
@@ -177,7 +177,7 @@ public class LodRegion
* TODO this will always return true unless it has
* @return true if the data was added successfully
*/
public boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data)
public boolean addVerticalData(byte detailLevel, int posX, int posZ, int[] color, int[] data, byte[] flags)
{
//position is already relative
//posX = LevelPosUtil.getRegionModule(detailLevel, posX);
@@ -188,29 +188,35 @@ public class LodRegion
if (this.dataContainer[detailLevel] == null)
this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
return this.dataContainer[detailLevel].addVerticalData(data, posX, posZ);
return this.dataContainer[detailLevel].addVerticalData(color, data, flags, posX, posZ);
}
/**
* Get the dataPoint at the given relative position.
* @return the data at the relative pos and detail level,
* 0 if the data doesn't exist.
*/
public long getData(byte detailLevel, int posX, int posZ, int verticalIndex)
public int getColor(byte detailLevel, int posX, int posZ, int verticalIndex)
{
return dataContainer[detailLevel].getColor(posX, posZ, verticalIndex);
}
public int getData(byte detailLevel, int posX, int posZ, int verticalIndex)
{
return dataContainer[detailLevel].getData(posX, posZ, verticalIndex);
}
public byte getFlags(byte detailLevel, int posX, int posZ, int verticalIndex)
{
return dataContainer[detailLevel].getFlags(posX, posZ, verticalIndex);
}
/**
* Get the dataPoint at the given relative position.
* Get the flags at the given relative position.
* @return the data at the relative pos and detail level,
* 0 if the data doesn't exist.
*/
public long getSingleData(byte detailLevel, int posX, int posZ)
public byte getSingleFlags(byte detailLevel, int posX, int posZ)
{
return dataContainer[detailLevel].getSingleData(posX, posZ);
return dataContainer[detailLevel].getSingleFlags(posX, posZ);
}
/**
* Clears the datapoint at the given relative position
*/
@@ -358,6 +364,7 @@ public class LodRegion
posZ + regionPosZ * size);
}
else
{
//if (desiredLevel > detailLevel)
//{
// we have gone beyond the target Detail level
@@ -408,6 +415,7 @@ public class LodRegion
}
}
}
}
}
@@ -479,7 +487,7 @@ public class LodRegion
if (dataContainer[detailLevel].doesItExist(posX, posZ))
// We take the bottom information always
// TODO what does that mean? bottom of what?
return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleData(posX, posZ));
return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleFlags(posX, posZ));
else
return DistanceGenerationMode.NONE.complexity;
}
@@ -37,14 +37,19 @@ public class VerticalLevelContainer implements LevelContainer
public final int size;
public final int maxVerticalData;
public final long[] dataContainer;
public final int[] dataContainerColor;
public final int[] dataContainerData;
public final byte[] dataContainerFlags;
public VerticalLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
maxVerticalData = DetailDistanceUtil.getMaxVerticalData(detailLevel);
dataContainer = new long[size * size * DetailDistanceUtil.getMaxVerticalData(detailLevel)];
final int i = size * size * maxVerticalData;
dataContainerColor = new int[i];
dataContainerData = new int[i];
dataContainerFlags = new byte[i];
}
@Override
@@ -60,47 +65,77 @@ public class VerticalLevelContainer implements LevelContainer
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
{
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = DataPointUtil.EMPTY_DATA;
final int i = (posX * size + posZ) * maxVerticalData + verticalIndex;
dataContainerColor[i] = 0;
dataContainerData[i] = 0;
dataContainerFlags[i] = 0;
}
}
@Override
public boolean addData(long data, int posX, int posZ, int verticalIndex)
public boolean addData(int color, int data, byte flags, int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = data;
final int i = (posX * size + posZ) * maxVerticalData + verticalIndex;
dataContainerColor[i] = color;
dataContainerData[i] = data;
dataContainerFlags[i] = flags;
return true;
}
@Override
public boolean addVerticalData(long[] data, int posX, int posZ)
public boolean addVerticalData(int[] color, int[] data, byte[] flags, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = data[verticalIndex];
{
final int i = (posX * size + posZ) * maxVerticalData + verticalIndex;
dataContainerColor[i] = color[verticalIndex];
dataContainerData[i] = data[verticalIndex];
dataContainerFlags[i] = flags[verticalIndex];
}
return true;
}
@Override
public boolean addSingleData(long data, int posX, int posZ)
public boolean addSingleData(int color, int data, byte flags, int posX, int posZ)
{
return addData(data, posX, posZ, 0);
return addData(color, data, flags, posX, posZ, 0);
}
@Override
public long getData(int posX, int posZ, int verticalIndex)
public int getColor(int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex];
return dataContainerColor[(posX * size + posZ) * maxVerticalData + verticalIndex];
}
@Override
public int getData(int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerData[(posX * size + posZ) * maxVerticalData + verticalIndex];
}
@Override
public long getSingleData(int posX, int posZ)
public byte getFlags(int posX, int posZ, int verticalIndex)
{
return getData(posX, posZ, 0);
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerFlags[(posX * size + posZ) * maxVerticalData + verticalIndex];
}
@Override
public byte getSingleFlags(int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerFlags[(posX * size + posZ) * maxVerticalData];
}
@Override
@@ -119,7 +154,7 @@ public class VerticalLevelContainer implements LevelContainer
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return DataPointUtil.doesItExist(getSingleData(posX, posZ));
return DataPointUtil.doesItExist(dataContainerFlags[(posX * size + posZ) * maxVerticalData]);
}
public VerticalLevelContainer(byte[] inputData, int version)
@@ -127,69 +162,131 @@ public class VerticalLevelContainer implements LevelContainer
int tempMaxVerticalData;
int tempIndex;
int index = 0;
long newData;
detailLevel = inputData[index];
index++;
tempMaxVerticalData = inputData[index] & 0b01111111;
index++;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int x = size * size * tempMaxVerticalData;
long[] tempDataContainer = new long[x];
int[] tempDataContainerColor = new int[x];
int[] tempDataContainerData = new int[x];
byte[] tempDataContainerFlags = new byte[x];
if (version == 6)
{
long oldData;
for (int i = 0; i < x; i++)
{
newData = 0;
oldData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
oldData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
newData = DataPointUtil.createDataPoint(
DataPointUtil.getAlpha(newData),
DataPointUtil.getRed(newData),
DataPointUtil.getGreen(newData),
DataPointUtil.getBlue(newData),
DataPointUtil.getHeight(newData) - DataPointUtil.VERTICAL_OFFSET,
DataPointUtil.getDepth(newData) - DataPointUtil.VERTICAL_OFFSET,
DataPointUtil.getLightSky(newData),
DataPointUtil.getLightBlock(newData),
DataPointUtil.getGenerationMode(newData),
DataPointUtil.getFlag(newData)
/*
|a |a |a |a |r |r |r |r |
|r |r |r |r |g |g |g |g |
|g |g |g |g |b |b |b |b |
|b |b |b |b |h |h |h |h |
|h |h |h |h |h |h |d |d |
|d |d |d |d |d |d |d |d |
|bl |bl |bl |bl |sl |sl |sl |sl |
|l |l |f |g |g |g |v |e |
*/
DataPointUtil.createDataPoint(
(int)((oldData >> 60) << 4) + 15,
(int)(oldData >> 52) & 0xFF,
(int)(oldData >> 44) & 0xFF,
(int)(oldData >> 36) & 0xFF,
(int)(oldData >> 26) & 0x3FF - DataPointUtil.VERTICAL_OFFSET,
(int)(oldData >> 16) & 0x3FF - DataPointUtil.VERTICAL_OFFSET,
(int)(oldData >> 8) & 0xF,
(int)(oldData >> 12) & 0xF,
(int)(oldData >> 5) & 0x1,
((oldData >> 5) & 0x1) == 1
);
tempDataContainer[i] = newData;
tempDataContainerColor[i] = ThreadMapUtil.dataPointColor;
tempDataContainerData[i] = ThreadMapUtil.dataPointData;
tempDataContainerFlags[i] = ThreadMapUtil.dataPointFlags;
}
}
else //if (version == 7)
else if (version == 7)
{
long oldData;
for (int i = 0; i < x; i++)
{
newData = 0;
oldData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
oldData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
tempDataContainer[i] = newData;
DataPointUtil.createDataPoint(
(int)((oldData >> 60) << 4) + 15,
(int)(oldData >> 52) & 0xFF,
(int)(oldData >> 44) & 0xFF,
(int)(oldData >> 36) & 0xFF,
(int)(oldData >> 26) & 0x3FF - DataPointUtil.VERTICAL_OFFSET - 64,
(int)(oldData >> 16) & 0x3FF - DataPointUtil.VERTICAL_OFFSET - 64,
(int)(oldData >> 8) & 0xF,
(int)(oldData >> 12) & 0xF,
(int)(oldData >> 5) & 0x1,
((oldData >> 5) & 0x1) == 1
);
tempDataContainerColor[i] = ThreadMapUtil.dataPointColor;
tempDataContainerData[i] = ThreadMapUtil.dataPointData;
tempDataContainerFlags[i] = ThreadMapUtil.dataPointFlags;
}
}
else //if (version == 8)
{
int color;
int data;
for (int i = 0; i < x; i++)
{
byte flags = inputData[index];
index++;
data = 0;
color = 0;
for (tempIndex = 0; tempIndex < 4; tempIndex++)
{
data += (((int) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
color += (((int) inputData[index + tempIndex + 4]) & 0xff) << (8 * tempIndex);
}
index += 8;
tempDataContainerColor[i] = color;
tempDataContainerData[i] = data;
tempDataContainerFlags[i] = flags;
}
}
if (tempMaxVerticalData > DetailDistanceUtil.getMaxVerticalData(detailLevel))
{
int tempMaxVerticalData2 = DetailDistanceUtil.getMaxVerticalData(detailLevel);
long[] dataToMerge = new long[tempMaxVerticalData];
long[] tempDataContainer2 = new long[size * size * tempMaxVerticalData2];
int[] dataToMergeColor = new int[tempMaxVerticalData];
int[] dataToMergeData = new int[tempMaxVerticalData];
byte[] dataToMergeFlags = new byte[tempMaxVerticalData];
int[] tempDataContainer2Color = new int[size * size * tempMaxVerticalData2];
int[] tempDataContainer2Data = new int[size * size * tempMaxVerticalData2];
byte[] tempDataContainer2Flags = new byte[size * size * tempMaxVerticalData2];
for (int i = 0; i < size * size; i++)
{
System.arraycopy(tempDataContainer, i * tempMaxVerticalData, dataToMerge, 0, tempMaxVerticalData);
dataToMerge = DataPointUtil.mergeMultiData(dataToMerge, tempMaxVerticalData, tempMaxVerticalData2);
System.arraycopy(dataToMerge, 0, tempDataContainer2, i * tempMaxVerticalData2, tempMaxVerticalData2);
System.arraycopy(tempDataContainerColor, i * tempMaxVerticalData, dataToMergeColor, 0, tempMaxVerticalData);
System.arraycopy(tempDataContainerData, i * tempMaxVerticalData, dataToMergeData, 0, tempMaxVerticalData);
System.arraycopy(tempDataContainerFlags, i * tempMaxVerticalData, dataToMergeFlags, 0, tempMaxVerticalData);
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, tempMaxVerticalData, tempMaxVerticalData2);
System.arraycopy(ThreadMapUtil.getRawVerticalDataArrayColor(), 0, tempDataContainer2Color, i * tempMaxVerticalData2, tempMaxVerticalData2);
System.arraycopy(ThreadMapUtil.getRawVerticalDataArrayData(), 0, tempDataContainer2Data, i * tempMaxVerticalData2, tempMaxVerticalData2);
System.arraycopy(ThreadMapUtil.getRawVerticalDataArrayFlags(), 0, tempDataContainer2Flags, i * tempMaxVerticalData2, tempMaxVerticalData2);
}
maxVerticalData = tempMaxVerticalData2;
this.dataContainer = tempDataContainer2;
this.dataContainerColor = tempDataContainer2Color;
this.dataContainerData = tempDataContainer2Data;
this.dataContainerFlags = tempDataContainer2Flags;
}
else
{
maxVerticalData = tempMaxVerticalData;
this.dataContainer = tempDataContainer;
this.dataContainerColor = tempDataContainerColor;
this.dataContainerData = tempDataContainerData;
this.dataContainerFlags = tempDataContainerFlags;
}
}
@@ -203,12 +300,13 @@ public class VerticalLevelContainer implements LevelContainer
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{
//We reset the array
long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(detailLevel);
int[] dataToMergeColor = ThreadMapUtil.getVerticalUpdateArrayColor(detailLevel);
int[] dataToMergeData = ThreadMapUtil.getVerticalUpdateArrayData(detailLevel);
byte[] dataToMergeFlags = ThreadMapUtil.getVerticalUpdateArrayFlags(detailLevel);
int lowerMaxVertical = dataToMerge.length / 4;
int lowerMaxVertical = dataToMergeFlags.length / 4;
int childPosX;
int childPosZ;
long[] data;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++)
@@ -218,12 +316,17 @@ public class VerticalLevelContainer implements LevelContainer
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++)
dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
{
final int i = (z * 2 + x) * lowerMaxVertical + verticalIndex;
dataToMergeColor[i] = lowerLevelContainer.getColor(childPosX, childPosZ, verticalIndex);
dataToMergeData[i] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
dataToMergeFlags[i] = lowerLevelContainer.getFlags(childPosX, childPosZ, verticalIndex);
}
}
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData());
addVerticalData(data, posX, posZ);
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, lowerMaxVertical, getMaxVerticalData());
addVerticalData(ThreadMapUtil.getRawVerticalDataArrayColor(), ThreadMapUtil.getRawVerticalDataArrayData(), ThreadMapUtil.getRawVerticalDataArrayFlags(), posX, posZ);
}
@Override
@@ -232,7 +335,8 @@ public class VerticalLevelContainer implements LevelContainer
int index = 0;
int x = size * size;
int tempIndex;
long current;
int currentColor;
int currentData;
boolean allGenerated = true;
byte[] tempData = ThreadMapUtil.getSaveContainer(detailLevel);
@@ -245,12 +349,18 @@ public class VerticalLevelContainer implements LevelContainer
{
for (j = 0; j < maxVerticalData; j++)
{
current = dataContainer[i * maxVerticalData + j];
for (tempIndex = 0; tempIndex < 8; tempIndex++)
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
currentColor = dataContainerColor[i * maxVerticalData + j];
currentData = dataContainerData[i * maxVerticalData + j];
tempData[index] = dataContainerFlags[i * maxVerticalData + j];
index++;
for (tempIndex = 0; tempIndex < 4; tempIndex++)
{
tempData[index + tempIndex] = (byte) (currentData >>> (8 * tempIndex));
tempData[index + tempIndex + 4] = (byte) (currentColor >>> (8 * tempIndex));
}
index += 8;
}
if(!DataPointUtil.doesItExist(dataContainer[i]))
if(!DataPointUtil.doesItExist(dataContainerFlags[i]))
allGenerated = false;
}
if (allGenerated)
@@ -57,9 +57,9 @@ public class DataPointUtil
//To be used in the future for negative value
//public final static int MIN_DEPTH = -64;
//public final static int MIN_HEIGHT = -64;
public final static int EMPTY_DATA = 0;
public static final short VERTICAL_OFFSET = -64;
public static int WORLD_HEIGHT = 1024;
public final static byte EMPTY_DATA = 0;
public static final short VERTICAL_OFFSET = -2048;
public static int WORLD_HEIGHT = 4096;
public final static int ALPHA_DOWNSIZE_SHIFT = 4;
@@ -68,167 +68,159 @@ public class DataPointUtil
//public final static int RED_COLOR_SHIFT = 16;
//public final static int ALPHA_COLOR_SHIFT = 24;
public final static int BLUE_SHIFT = 36;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24;
public final static byte BLUE_SHIFT = 0;
public final static byte GREEN_SHIFT = 8;
public final static byte RED_SHIFT = 16;
public final static byte ALPHA_SHIFT = 24;
public final static int COLOR_SHIFT = 36;
//public final static byte COLOR_SHIFT = 36;
public final static int HEIGHT_SHIFT = 26;
public final static int DEPTH_SHIFT = 16;
public final static int BLOCK_LIGHT_SHIFT = 12;
public final static int SKY_LIGHT_SHIFT = 8;
//public final static int LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
//public final static int VERTICAL_INDEX_SHIFT = 6;
public final static int FLAG_SHIFT = 5;
public final static int GEN_TYPE_SHIFT = 2;
public final static int VOID_SHIFT = 1;
public final static int EXISTENCE_SHIFT = 0;
public final static byte HEIGHT_SHIFT = 20;
public final static byte DEPTH_SHIFT = 8;
public final static byte BLOCK_LIGHT_SHIFT = 4;
public final static byte SKY_LIGHT_SHIFT = 0;
//public final static byte LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
//public final static byte VERTICAL_INDEX_SHIFT = 6;
public final static byte FLAG_SHIFT = 5;
public final static byte GEN_TYPE_SHIFT = 2;
public final static byte VOID_SHIFT = 1;
public final static byte EXISTENCE_SHIFT = 0;
public final static long ALPHA_MASK = 0b1111;
public final static long RED_MASK = 0b1111_1111;
public final static long GREEN_MASK = 0b1111_1111;
public final static long BLUE_MASK = 0b1111_1111;
public final static long COLOR_MASK = 0b11111111_11111111_11111111;
public final static long HEIGHT_MASK = 0b11_1111_1111;
public final static long DEPTH_MASK = 0b11_1111_1111;
//public final static long LIGHTS_MASK = 0b1111_1111;
public final static long BLOCK_LIGHT_MASK = 0b1111;
public final static long SKY_LIGHT_MASK = 0b1111;
//public final static long VERTICAL_INDEX_MASK = 0b11;
public final static long FLAG_MASK = 0b1;
public final static long GEN_TYPE_MASK = 0b111;
public final static long VOID_MASK = 1;
public final static long EXISTENCE_MASK = 1;
public final static int ALPHA_MASK = 0xFF;
public final static int RED_MASK = 0xFF;
public final static int GREEN_MASK = 0xFF;
public final static int BLUE_MASK = 0xFF;
public final static int COLOR_MASK = 0xFFFFFFFF;
public final static int HEIGHT_MASK = 0xFFF;
public final static int DEPTH_MASK = 0xFFF;
public final static int LIGHTS_MASK = 0xFF;
public final static int BLOCK_LIGHT_MASK = 0xF;
public final static int SKY_LIGHT_MASK = 0xF;
public final static int VERTICAL_INDEX_MASK = 0x3;
public final static byte FLAG_MASK = 0x1;
public final static byte GEN_TYPE_MASK = 0x7;
public final static byte VOID_MASK = 1;
public final static byte EXISTENCE_MASK = 1;
public static long createVoidDataPoint(int generationMode)
/** Returns the Flags byte */
public static byte createVoidDataPoint(byte generationMode)
{
long dataPoint = 0;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
dataPoint += VOID_MASK << VOID_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
generationMode = (byte) ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT);
generationMode |= VOID_MASK << VOID_SHIFT;
generationMode |= EXISTENCE_MASK << EXISTENCE_SHIFT;
return generationMode;
}
public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode, boolean flag)
/** Returned datapoint is in ThreadMapUtil */
public static void createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode, boolean flag)
{
return createDataPoint(
ColorUtil.getAlpha(color),
ColorUtil.getRed(color),
ColorUtil.getGreen(color),
ColorUtil.getBlue(color),
height, depth, lightSky, lightBlock, generationMode, flag);
int data = (height & HEIGHT_MASK) << HEIGHT_SHIFT;
data += (depth & DEPTH_MASK) << DEPTH_SHIFT;
data += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
data += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
byte flags = (byte) ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT);
if (flag) flags += FLAG_MASK << FLAG_SHIFT;
flags += EXISTENCE_MASK << EXISTENCE_SHIFT;
ThreadMapUtil.saveDataPoint(color, data, flags);
}
public static long createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode, boolean flag)
public static void createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode, boolean flag)
{
long dataPoint = 0;
dataPoint += (long) (alpha >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT;
dataPoint += (red & RED_MASK) << RED_SHIFT;
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT;
dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT;
dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT;
dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT;
dataPoint += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
dataPoint += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
if (flag) dataPoint += FLAG_MASK << FLAG_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
createDataPoint(
height, depth,
(alpha << ALPHA_SHIFT) | (red << RED_SHIFT) | (green << GREEN_SHIFT) | blue,
lightSky, lightBlock, generationMode, flag);
}
public static short getHeight(long dataPoint)
public static short getHeight(int data)
{
return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK);
return (short) ((data >>> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(long dataPoint)
public static short getDepth(int data)
{
return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK);
return (short) ((data >>> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getAlpha(long dataPoint)
public static short getAlpha(int color)
{
return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111);
return (short) ((color >>> ALPHA_SHIFT) & ALPHA_MASK);
}
public static short getRed(long dataPoint)
public static short getRed(int color)
{
return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK);
return (short) ((color >>> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
public static short getGreen(int color)
{
return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK);
return (short) ((color >>> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
public static short getBlue(int color)
{
return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK);
return (short) ((color >>> BLUE_SHIFT) & BLUE_MASK);
}
public static byte getLightSky(long dataPoint)
public static byte getLightSky(int data)
{
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
return (byte) ((data >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightSkyAlt(long dataPoint)
public static byte getLightSkyAlt(int data, byte flags)
{
if (skyLightPlayer == 0 && ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1)
if (skyLightPlayer == 0 && ((flags >>> FLAG_SHIFT) & FLAG_MASK) == 1)
return 0;
else
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
return (byte) ((data >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightBlock(long dataPoint)
public static byte getLightBlock(int data)
{
return (byte) ((dataPoint >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
return (byte) ((data >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
public static boolean getFlag(long dataPoint)
public static boolean getFlag(byte flags)
{
return ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1;
return ((flags >>> FLAG_SHIFT) & FLAG_MASK) == 1;
}
public static byte getGenerationMode(long dataPoint)
public static byte getGenerationMode(byte flags)
{
return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
return (byte) ((flags >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
}
public static boolean isVoid(long dataPoint)
public static boolean isVoid(byte flags)
{
return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1);
return (((flags >>> VOID_SHIFT) & VOID_MASK) == 1);
}
public static boolean doesItExist(long dataPoint)
public static boolean doesItExist(byte flags)
{
return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
return ((flags >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1;
}
public static int getColor(long dataPoint)
@Deprecated
public static int getColor(int color)
{
return (int) (((dataPoint >>> COLOR_SHIFT) & COLOR_MASK) | (/*((dataPoint >>> (ALPHA_SHIFT - ALPHA_DOWNSIZE_SHIFT)) | 0b1111)*/255 << 24));
return color;
}
/** This is used to convert a dataPoint to string (useful for the print function) */
@SuppressWarnings("unused")
public static String toString(long dataPoint)
public static String toString(int color, int data, byte flags)
{
return getHeight(dataPoint) + " " +
getDepth(dataPoint) + " " +
getAlpha(dataPoint) + " " +
getRed(dataPoint) + " " +
getBlue(dataPoint) + " " +
getGreen(dataPoint) + " " +
getLightBlock(dataPoint) + " " +
getLightSky(dataPoint) + " " +
getGenerationMode(dataPoint) + " " +
isVoid(dataPoint) + " " +
doesItExist(dataPoint) + '\n';
return getHeight(data) + " " +
getDepth(data) + " " +
getAlpha(color) + " " +
getRed(color) + " " +
getBlue(color) + " " +
getGreen(color) + " " +
getLightBlock(data) + " " +
getLightSky(data) + " " +
getGenerationMode(flags) + " " +
isVoid(flags) + " " +
doesItExist(flags) + '\n';
}
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize)
@@ -258,25 +250,30 @@ public class DataPointUtil
/**
* This method merge column of multiple data together
* @param dataToMerge one or more columns of data
* Returned datapoint is in ThreadMapUtil
* @param dataToMergeColor colors of one or more columns of data
* @param dataToMergeData data of one or more columns of data
* @param dataToMergeFlags flags of one or more columns of data
* @param inputVerticalData vertical size of an input data
* @param maxVerticalData max vertical size of the merged data
* @return one column of correctly parsed data
*/
public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData)
public static void mergeMultiData(int[] dataToMergeColor, int[] dataToMergeData, byte[] dataToMergeFlags, int inputVerticalData, int maxVerticalData)
{
int size = dataToMerge.length / inputVerticalData;
int size = dataToMergeData.length / inputVerticalData;
// We initialize the arrays that are going to be used
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((WORLD_HEIGHT / 2 + 1) * 2);
long[] dataPoint = ThreadMapUtil.getVerticalDataArray(DetailDistanceUtil.getMaxVerticalData(0));
int[] dataPointColor = ThreadMapUtil.getVerticalDataArrayColor(DetailDistanceUtil.getMaxVerticalData(0));
int[] dataPointData = ThreadMapUtil.getVerticalDataArrayData(DetailDistanceUtil.getMaxVerticalData(0));
byte[] dataPointFlags = ThreadMapUtil.getVerticalDataArrayFlags(DetailDistanceUtil.getMaxVerticalData(0));
int genMode = DistanceGenerationMode.FULL.complexity;
byte genMode = DistanceGenerationMode.FULL.complexity;
boolean allEmpty = true;
boolean allVoid = true;
boolean allDefault;
long singleData;
int singleDataData;
byte singleDataFlags;
short depth;
@@ -290,16 +287,17 @@ public class DataPointUtil
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (doesItExist(singleData))
singleDataData = dataToMergeData[index * inputVerticalData + dataIndex];
singleDataFlags = dataToMergeFlags[index * inputVerticalData + dataIndex];
if (doesItExist(singleDataFlags))
{
genMode = Math.min(genMode, getGenerationMode(singleData));
genMode = (byte) Math.min(genMode, getGenerationMode(singleDataFlags));
allEmpty = false;
if (!isVoid(singleData))
if (!isVoid(singleDataFlags))
{
allVoid = false;
depth = getDepth(singleData);
height = getHeight(singleData);
depth = getDepth(singleDataData);
height = getHeight(singleDataData);
int botPos = -1;
int topPos = -1;
@@ -402,11 +400,11 @@ public class DataPointUtil
//We check if there is any data that's not empty or void
if (allEmpty)
return dataPoint;
return;
if (allVoid)
{
dataPoint[0] = createVoidDataPoint(genMode);
return dataPoint;
dataPointFlags[0] = createVoidDataPoint(genMode);
return;
}
//we limit the vertical portion to maxVerticalData
@@ -451,71 +449,90 @@ public class DataPointUtil
allEmpty = true;
allVoid = true;
allDefault = true;
long data = 0;
int singleDataColor;
int data = EMPTY_DATA;
int color = EMPTY_DATA;
byte flags = EMPTY_DATA;
for (int index = 0; index < size; index++)
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (doesItExist(singleData) && !isVoid(singleData))
singleDataColor = dataToMergeColor[index * inputVerticalData + dataIndex];
singleDataData = dataToMergeData[index * inputVerticalData + dataIndex];
singleDataFlags = dataToMergeFlags[index * inputVerticalData + dataIndex];
if (doesItExist(singleDataFlags) && !isVoid(singleDataFlags))
{
if ((depth <= getDepth(singleData) && getDepth(singleData) <= height)
|| (depth <= getHeight(singleData) && getHeight(singleData) <= height))
if ((depth <= getDepth(singleDataData) && getDepth(singleDataData) <= height)
|| (depth <= getHeight(singleDataData) && getHeight(singleDataData) <= height))
{
if (getHeight(singleData) > getHeight(data))
data = singleData;
if (getHeight(singleDataData) > getHeight(data))
{
color = singleDataColor;
data = singleDataData;
flags = singleDataFlags;
}
}
}
else
break;
}
if (!doesItExist(data))
if (!doesItExist(flags))
{
singleData = dataToMerge[index * inputVerticalData];
data = createVoidDataPoint(getGenerationMode(singleData));
singleDataFlags = dataToMergeFlags[index * inputVerticalData];
if (doesItExist(singleDataFlags))
flags = createVoidDataPoint(getGenerationMode(singleDataFlags));
else
flags = createVoidDataPoint((byte) 0);
data = EMPTY_DATA;
color = EMPTY_DATA;
}
if (doesItExist(data))
if (doesItExist(flags))
{
allEmpty = false;
if (!isVoid(data))
if (!isVoid(flags))
{
numberOfChildren++;
allVoid = false;
tempAlpha += getAlpha(data);
tempRed += getRed(data);
tempGreen += getGreen(data);
tempBlue += getBlue(data);
tempAlpha += getAlpha(color);
tempRed += getRed(color);
tempGreen += getGreen(color);
tempBlue += getBlue(color);
tempLightBlock += getLightBlock(data);
tempLightSky += getLightSky(data);
if (!getFlag(data)) allDefault = false;
if (!getFlag(flags))
allDefault = false;
}
tempGenMode = (byte) Math.min(tempGenMode, getGenerationMode(data));
tempGenMode = (byte) Math.min(tempGenMode, getGenerationMode(flags));
}
else
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
}
if (allEmpty)
//no child has been initialized
dataPoint[j] = EMPTY_DATA;
else if (allVoid)
//all the children are void
dataPoint[j] = createVoidDataPoint(tempGenMode);
else
if (!allEmpty)
{
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
dataPoint[j] = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
//child has been initialized
if (allVoid)
{
//all the children are void
dataPointFlags[j] = createVoidDataPoint(tempGenMode);
}
else
{
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
dataPointColor[j] = ThreadMapUtil.dataPointColor;
dataPointData[j] = ThreadMapUtil.dataPointData;
dataPointFlags[j] = ThreadMapUtil.dataPointFlags;
}
}
}
return dataPoint;
}
}
@@ -39,7 +39,7 @@ public class DetailDistanceUtil
private static final double treeGenMultiplier = 1.0;
private static final double treeCutMultiplier = 1.0;
private static byte minGenDetail = CONFIG.client().graphics().quality().getDrawResolution().detailLevel;
private static byte minDrawDetail = (byte) Math.max(CONFIG.client().graphics().quality().getDrawResolution().detailLevel, CONFIG.client().graphics().quality().getDrawResolution().detailLevel);
private static byte minDrawDetail = CONFIG.client().graphics().quality().getDrawResolution().detailLevel;
private static final int maxDetail = LodUtil.REGION_DETAIL_LEVEL + 1;
private static final int minDistance = 0;
private static int minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f);
@@ -79,7 +79,7 @@ public class DetailDistanceUtil
if (CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
return detail * 0x10000; //if you want more you are doing wrong
int distanceUnit = CONFIG.client().graphics().quality().getHorizontalScale().distanceUnit;
int distanceUnit = CONFIG.client().graphics().quality().getHorizontalScale() * 16;
if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
return (detail * distanceUnit);
else
@@ -96,14 +96,14 @@ public class DetailDistanceUtil
public static byte baseInverseFunction(int distance, byte minDetail, boolean useRenderMinDistance)
{
int detail;
byte detail;
if (distance == 0
|| (distance < minDetailDistance && useRenderMinDistance)
|| CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
return minDetail;
int distanceUnit = CONFIG.client().graphics().quality().getHorizontalScale().distanceUnit;
int distanceUnit = CONFIG.client().graphics().quality().getHorizontalScale() * 16;
if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
detail = (byte) distance / distanceUnit;
detail = (byte) (distance / distanceUnit);
else
{
double base = CONFIG.client().graphics().quality().getHorizontalQuality().quadraticBase;
@@ -139,12 +139,12 @@ public class DetailDistanceUtil
return CONFIG.client().worldGenerator().getDistanceGenerationMode();
}
public static byte getLodDrawDetail(int detail)
public static byte getLodDrawDetail(byte detail)
{
if (detail < minDrawDetail)
return minDrawDetail;
else
return (byte) detail;
detail += minDrawDetail;
if (detail > 10)
detail = 10;
return detail;
}
public static HorizontalResolution getLodGenDetail(int detail)
@@ -26,7 +26,7 @@ import java.util.HashSet;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.config.HorizontalResolution;
import com.seibel.lod.core.enums.config.VanillaOverdraw;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.lod.RegionPos;
import com.seibel.lod.core.objects.opengl.DefaultLodVertexFormats;
@@ -403,10 +403,10 @@ public class LodUtil
return false;
int tempX;
int tempZ;
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS)
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
{
tempX = x + Box.DIRECTION_NORMAL_MAP.get(lodDirection).x;
tempZ = z + Box.DIRECTION_NORMAL_MAP.get(lodDirection).z;
tempX = x + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).x;
tempZ = z + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).z;
if (vanillaRenderedChunks[x][z] || (!(tempX < 0 || tempZ < 0 || tempX >= vanillaRenderedChunks.length || tempZ >= vanillaRenderedChunks[0].length)
&& !vanillaRenderedChunks[tempX][tempZ]))
return true;
@@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.objects.Box;
import com.seibel.lod.core.objects.VertexOptimizer;
/**
* Holds data used by specific threads so
@@ -38,15 +38,18 @@ import com.seibel.lod.core.objects.Box;
*/
public class ThreadMapUtil
{
public static final ConcurrentMap<String, long[]> threadSingleUpdateMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> threadBuilderArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadVerticalAddDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> threadBuilderVerticalArrayMapColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> threadBuilderVerticalArrayMapData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[][]> threadBuilderVerticalArrayMapFlags = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[]> threadVerticalAddDataMapColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[]> threadVerticalAddDataMapData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[]> threadVerticalAddDataMapFlags = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[][]> saveContainer = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, short[]> projectionArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, short[]> heightAndDepthMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> verticalUpdate = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> verticalUpdateColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> verticalUpdateData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[][]> verticalUpdateFlags = new ConcurrentHashMap<>();
//________________________//
@@ -54,8 +57,13 @@ public class ThreadMapUtil
//________________________//
public static final ConcurrentMap<String, boolean[]> adjShadeDisabled = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, long[]>> adjDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Box> boxMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, int[]>> adjDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, byte[]>> adjFlagsMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, VertexOptimizer> boxMap = new ConcurrentHashMap<>();
public static int dataPointColor = 0;
public static int dataPointData = 0;
public static byte dataPointFlags = 0;
@@ -65,14 +73,14 @@ public class ThreadMapUtil
if (!adjShadeDisabled.containsKey(Thread.currentThread().getName())
|| (adjShadeDisabled.get(Thread.currentThread().getName()) == null))
{
adjShadeDisabled.put(Thread.currentThread().getName(), new boolean[Box.DIRECTIONS.length]);
adjShadeDisabled.put(Thread.currentThread().getName(), new boolean[VertexOptimizer.DIRECTIONS.length]);
}
Arrays.fill(adjShadeDisabled.get(Thread.currentThread().getName()), false);
return adjShadeDisabled.get(Thread.currentThread().getName());
}
/** returns the array NOT cleared every time */
public static Map<LodDirection, long[]> getAdjDataArray(int verticalData)
public static Map<LodDirection, int[]> getAdjDataArray(int verticalData)
{
if (!adjDataMap.containsKey(Thread.currentThread().getName())
|| (adjDataMap.get(Thread.currentThread().getName()) == null)
@@ -80,26 +88,47 @@ public class ThreadMapUtil
|| (adjDataMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData))
{
adjDataMap.put(Thread.currentThread().getName(), new HashMap<>());
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new long[1]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new long[1]);
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS)
adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new long[verticalData]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new int[1]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new int[1]);
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new int[verticalData]);
}
else
{
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS)
Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), DataPointUtil.EMPTY_DATA);
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), 0);
}
return adjDataMap.get(Thread.currentThread().getName());
}
public static Box getBox()
/** returns the array NOT cleared every time */
public static Map<LodDirection, byte[]> getAdjFlagsArray(int verticalData)
{
if (!adjFlagsMap.containsKey(Thread.currentThread().getName())
|| (adjFlagsMap.get(Thread.currentThread().getName()) == null)
|| (adjFlagsMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH) == null)
|| (adjFlagsMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData))
{
adjFlagsMap.put(Thread.currentThread().getName(), new HashMap<>());
adjFlagsMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new byte[1]);
adjFlagsMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new byte[1]);
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
adjFlagsMap.get(Thread.currentThread().getName()).put(lodDirection, new byte[verticalData]);
}
else
{
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
Arrays.fill(adjFlagsMap.get(Thread.currentThread().getName()).get(lodDirection), (byte) 0);
}
return adjFlagsMap.get(Thread.currentThread().getName());
}
public static VertexOptimizer getBox()
{
if (!boxMap.containsKey(Thread.currentThread().getName())
|| (boxMap.get(Thread.currentThread().getName()) == null))
{
boxMap.put(Thread.currentThread().getName(), new Box());
boxMap.put(Thread.currentThread().getName(), new VertexOptimizer());
}
boxMap.get(Thread.currentThread().getName()).reset();
return boxMap.get(Thread.currentThread().getName());
@@ -119,21 +148,57 @@ public class ThreadMapUtil
/** returns the array filled with 0's */
public static long[] getBuilderVerticalArray(int detailLevel)
public static int[] getBuilderVerticalArrayColor(int detailLevel)
{
if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null))
if (!threadBuilderVerticalArrayMapColor.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[5][];
int[][] array = new int[5][];
int size;
for (int i = 0; i < 5; i++)
{
size = 1 << i;
array[i] = new long[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
array[i] = new int[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
}
threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array);
threadBuilderVerticalArrayMapColor.put(Thread.currentThread().getName(), array);
}
Arrays.fill(threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel];
Arrays.fill(threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static int[] getBuilderVerticalArrayData(int detailLevel)
{
if (!threadBuilderVerticalArrayMapData.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMapData.get(Thread.currentThread().getName()) == null))
{
int[][] array = new int[5][];
int size;
for (int i = 0; i < 5; i++)
{
size = 1 << i;
array[i] = new int[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
}
threadBuilderVerticalArrayMapData.put(Thread.currentThread().getName(), array);
}
Arrays.fill(threadBuilderVerticalArrayMapData.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMapData.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static byte[] getBuilderVerticalArrayFlags(int detailLevel)
{
if (!threadBuilderVerticalArrayMapFlags.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMapFlags.get(Thread.currentThread().getName()) == null))
{
byte[][] array = new byte[5][];
int size;
for (int i = 0; i < 5; i++)
{
size = 1 << i;
array[i] = new byte[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
}
threadBuilderVerticalArrayMapFlags.put(Thread.currentThread().getName(), array);
}
Arrays.fill(threadBuilderVerticalArrayMapFlags.get(Thread.currentThread().getName())[detailLevel], (byte) 0);
return threadBuilderVerticalArrayMapFlags.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array NOT cleared every time */
@@ -145,7 +210,7 @@ public class ThreadMapUtil
int size = 1;
for (int i = LodUtil.DETAIL_OPTIONS - 1; i >= 0; i--)
{
array[i] = new byte[2 + 8 * size * size * DetailDistanceUtil.getMaxVerticalData(i)];
array[i] = new byte[2 + 9 * size * size * DetailDistanceUtil.getMaxVerticalData(i)];
size = size << 1;
}
saveContainer.put(Thread.currentThread().getName(), array);
@@ -156,19 +221,46 @@ public class ThreadMapUtil
/** returns the array filled with 0's */
public static long[] getVerticalDataArray(int arrayLength)
public static int[] getVerticalDataArrayColor(int arrayLength)
{
if (!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[arrayLength]);
}
if (!threadVerticalAddDataMapColor.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapColor.get(Thread.currentThread().getName()) == null))
threadVerticalAddDataMapColor.put(Thread.currentThread().getName(), new int[arrayLength]);
else
{
Arrays.fill(threadVerticalAddDataMap.get(Thread.currentThread().getName()), 0);
}
return threadVerticalAddDataMap.get(Thread.currentThread().getName());
Arrays.fill(threadVerticalAddDataMapColor.get(Thread.currentThread().getName()), 0);
return threadVerticalAddDataMapColor.get(Thread.currentThread().getName());
}
public static int[] getRawVerticalDataArrayColor()
{
return threadVerticalAddDataMapColor.get(Thread.currentThread().getName());
}
/** returns the array filled with 0's */
public static int[] getVerticalDataArrayData(int arrayLength)
{
if (!threadVerticalAddDataMapData.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapData.get(Thread.currentThread().getName()) == null))
threadVerticalAddDataMapData.put(Thread.currentThread().getName(), new int[arrayLength]);
else
Arrays.fill(threadVerticalAddDataMapData.get(Thread.currentThread().getName()), 0);
return threadVerticalAddDataMapData.get(Thread.currentThread().getName());
}
public static int[] getRawVerticalDataArrayData()
{
return threadVerticalAddDataMapData.get(Thread.currentThread().getName());
}
/** returns the array filled with 0's */
public static byte[] getVerticalDataArrayFlags(int arrayLength)
{
if (!threadVerticalAddDataMapFlags.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapFlags.get(Thread.currentThread().getName()) == null))
threadVerticalAddDataMapFlags.put(Thread.currentThread().getName(), new byte[arrayLength]);
else
Arrays.fill(threadVerticalAddDataMapFlags.get(Thread.currentThread().getName()), (byte) 0);
return threadVerticalAddDataMapFlags.get(Thread.currentThread().getName());
}
public static byte[] getRawVerticalDataArrayFlags()
{
return threadVerticalAddDataMapFlags.get(Thread.currentThread().getName());
}
/** returns the array NOT cleared every time */
@@ -181,22 +273,49 @@ public class ThreadMapUtil
return heightAndDepthMap.get(Thread.currentThread().getName());
}
/** returns the array filled with 0's */
public static long[] getVerticalUpdateArray(int detailLevel)
public static int[] getVerticalUpdateArrayColor(int detailLevel)
{
if (!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null))
if (!verticalUpdateColor.containsKey(Thread.currentThread().getName()) || (verticalUpdateColor.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[LodUtil.DETAIL_OPTIONS][];
int[][] array = new int[LodUtil.DETAIL_OPTIONS][];
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new long[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdate.put(Thread.currentThread().getName(), array);
array[i] = new int[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdateColor.put(Thread.currentThread().getName(), array);
}
else
Arrays.fill(verticalUpdateColor.get(Thread.currentThread().getName())[detailLevel], 0);
return verticalUpdateColor.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static int[] getVerticalUpdateArrayData(int detailLevel)
{
if (!verticalUpdateData.containsKey(Thread.currentThread().getName()) || (verticalUpdateData.get(Thread.currentThread().getName()) == null))
{
Arrays.fill(verticalUpdate.get(Thread.currentThread().getName())[detailLevel], 0);
int[][] array = new int[LodUtil.DETAIL_OPTIONS][];
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new int[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdateData.put(Thread.currentThread().getName(), array);
}
return verticalUpdate.get(Thread.currentThread().getName())[detailLevel];
else
Arrays.fill(verticalUpdateData.get(Thread.currentThread().getName())[detailLevel], 0);
return verticalUpdateData.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static byte[] getVerticalUpdateArrayFlags(int detailLevel)
{
if (!verticalUpdateFlags.containsKey(Thread.currentThread().getName()) || (verticalUpdateFlags.get(Thread.currentThread().getName()) == null))
{
byte[][] array = new byte[LodUtil.DETAIL_OPTIONS][];
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new byte[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdateFlags.put(Thread.currentThread().getName(), array);
}
else
Arrays.fill(verticalUpdateFlags.get(Thread.currentThread().getName())[detailLevel], (byte) 0);
return verticalUpdateFlags.get(Thread.currentThread().getName())[detailLevel];
}
/** clears all arrays so they will have to be rebuilt */
@@ -205,14 +324,24 @@ public class ThreadMapUtil
adjShadeDisabled.clear();
adjDataMap.clear();
boxMap.clear();
threadSingleUpdateMap.clear();
threadBuilderArrayMap.clear();
threadBuilderVerticalArrayMap.clear();
threadVerticalAddDataMap.clear();
threadBuilderVerticalArrayMapColor.clear();
threadBuilderVerticalArrayMapData.clear();
threadBuilderVerticalArrayMapFlags.clear();
threadVerticalAddDataMapColor.clear();
threadVerticalAddDataMapData.clear();
threadVerticalAddDataMapFlags.clear();
saveContainer.clear();
projectionArrayMap.clear();
heightAndDepthMap.clear();
singleDataToMergeMap.clear();
verticalUpdate.clear();
verticalUpdateColor.clear();
verticalUpdateData.clear();
verticalUpdateFlags.clear();
}
public static void saveDataPoint(int color, int data, byte flags)
{
dataPointColor = color;
dataPointData = data;
dataPointFlags = flags;
}
}
@@ -76,6 +76,7 @@ public interface ILodConfigWrapperSingleton
HorizontalResolution DRAW_RESOLUTION_DEFAULT = HorizontalResolution.BLOCK;
String DRAW_RESOLUTION_DESC = ""
+ " What is the maximum detail fake chunks should be drawn at? \n"
+ " This setting will only affect closer chunks.\n"
+ " Higher settings will increase memory and GPU usage. \n"
+ "\n"
+ " " + HorizontalResolution.CHUNK + ": render 1 LOD for each Chunk. \n"
@@ -111,20 +112,13 @@ public interface ILodConfigWrapperSingleton
VerticalQuality getVerticalQuality();
void setVerticalQuality(VerticalQuality newVerticalQuality);
HorizontalScale HORIZONTAL_SCALE_DEFAULT = HorizontalScale.MEDIUM;
MinDefaultMax<Integer> HORIZONTAL_SCALE_MIN_DEFAULT_MAX = new MinDefaultMax<Integer>(2, 8, 32);
String HORIZONTAL_SCALE_DESC = ""
+ " This indicates how quickly fake chunks decrease in quality the further away they are. \n"
+ " Higher settings will render higher quality fake chunks farther away, \n"
+ " but will increase memory and GPU usage. \n"
+ "\n"
+ " " + HorizontalScale.LOW + ": quality drops every " + HorizontalScale.LOW.distanceUnit / 16 + " chunks. \n"
+ " " + HorizontalScale.MEDIUM + ": quality drops every " + HorizontalScale.MEDIUM.distanceUnit / 16 + " chunks. \n"
+ " " + HorizontalScale.HIGH + ": quality drops every " + HorizontalScale.HIGH.distanceUnit / 16 + " chunks. \n"
+ "\n"
+ " Lowest Quality: " + HorizontalScale.LOW
+ " Highest Quality: " + HorizontalScale.HIGH;
HorizontalScale getHorizontalScale();
void setHorizontalScale(HorizontalScale newHorizontalScale);
+ " but will increase memory and GPU usage.";
int getHorizontalScale();
void setHorizontalScale(int newHorizontalScale);
HorizontalQuality HORIZONTAL_QUALITY_DEFAULT = HorizontalQuality.MEDIUM;
String HORIZONTAL_QUALITY_DESC = ""