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 org.apache.logging.log4j.Logger;
import com.seibel.lod.core.ModInfo; 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.lod.LodDimension;
import com.seibel.lod.core.objects.math.Mat4f; import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.render.GLProxy; import com.seibel.lod.core.render.GLProxy;
import com.seibel.lod.core.render.LodRenderer; import com.seibel.lod.core.render.LodRenderer;
import com.seibel.lod.core.util.DetailDistanceUtil; import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.SingletonHandler; 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.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
@@ -76,7 +74,7 @@ public class ClientApi
public void renderLods(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks) public void renderLods(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks)
{ {
// comment out when creating a release // comment out when creating a release
// applyConfigOverrides(); applyConfigOverrides();
// clear any out of date objects // clear any out of date objects
MC.clearFrameObjectCache(); MC.clearFrameObjectCache();
@@ -148,7 +146,8 @@ public class ClientApi
configOverrideReminderPrinted = true; configOverrideReminderPrinted = true;
} }
// CONFIG.client().worldGenerator().setDistanceGenerationMode(DistanceGenerationMode.SURFACE); // CONFIG.client().worldGenerator().setDistanceGenerationMode(DistanceGenerationMode.FULL);
// CONFIG.client().worldGenerator().setGenerationPriority(GenerationPriority.AUTO); // CONFIG.client().worldGenerator().setGenerationPriority(GenerationPriority.AUTO);
// CONFIG.client().graphics().advancedGraphics().setGpuUploadMethod(GpuUploadMethod.BUFFER_STORAGE); // CONFIG.client().graphics().advancedGraphics().setGpuUploadMethod(GpuUploadMethod.BUFFER_STORAGE);
@@ -180,14 +179,6 @@ public class ClientApi
firstTimeSetupComplete = true; 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 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.builders.worldGeneration.LodWorldGenerator;
import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.objects.lod.LodDimension; import com.seibel.lod.core.objects.lod.LodDimension;
@@ -115,13 +116,30 @@ public class EventApi
ClientApi.renderer.regenerateLODsNextFrame(); ClientApi.renderer.regenerateLODsNextFrame();
} }
/** This is also called when the user disconnects from a server+ */
public void worldUnloadEvent() public void worldUnloadEvent()
{ {
// the player just unloaded a world/dimension // the player just unloaded a world/dimension
ThreadMapUtil.clearMaps(); 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 // 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 // if this isn't done unfinished tasks may be left in the queue
// preventing new LodChunks form being generated // preventing new LodChunks form being generated
//LodNodeGenWorker.restartExecutorService(); // TODO why was this commented out? -James LodGenWorker.restartExecutorService();
//ThreadMapUtil.clearMaps();
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0); LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
ApiShared.lodWorld.deselectWorld(); ApiShared.lodWorld.deselectWorld();
// prevent issues related to the buffer builder // prevent issues related to the buffer builder
// breaking when changing worlds. // breaking or retaining previous data when changing worlds.
ClientApi.renderer.destroyBuffers(); ClientApi.renderer.destroyBuffers();
recalculateWidths = true; recalculateWidths = true;
ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory); ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory);
@@ -30,6 +30,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import com.seibel.lod.core.objects.VertexOptimizer;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30; 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.GpuUploadMethod;
import com.seibel.lod.core.enums.config.VanillaOverdraw; import com.seibel.lod.core.enums.config.VanillaOverdraw;
import com.seibel.lod.core.enums.rendering.GLProxyContext; 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.PosToRenderContainer;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.lod.LodDimension; import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.lod.LodRegion; import com.seibel.lod.core.objects.lod.LodRegion;
import com.seibel.lod.core.objects.lod.RegionPos; 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 */ /** this is used to prevent multiple threads creating, destroying, or using the buffers at the same time */
private final ReentrantLock bufferLock = new ReentrantLock(); private final ReentrantLock bufferLock = new ReentrantLock();
private volatile Box[][] boxCache; private volatile VertexOptimizer[][] vertexOptimizerCache;
private volatile PosToRenderContainer[][] setsToRender; private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center; private volatile RegionPos center;
@@ -184,6 +185,10 @@ public class LodBufferBuilderFactory
// setupBuffers hasn't been called yet // setupBuffers hasn't been called yet
return; return;
if (MC.getCurrentLightMap() == null)
// the lighting hasn't loaded yet
return;
generatingBuffers = true; generatingBuffers = true;
@@ -224,11 +229,11 @@ public class LodBufferBuilderFactory
if (setsToRender.length != lodDim.getWidth()) if (setsToRender.length != lodDim.getWidth())
setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()]; setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()];
if (boxCache == null) if (vertexOptimizerCache == null)
boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()]; vertexOptimizerCache = new VertexOptimizer[lodDim.getWidth()][lodDim.getWidth()];
if (boxCache.length != lodDim.getWidth()) if (vertexOptimizerCache.length != lodDim.getWidth())
boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()]; vertexOptimizerCache = new VertexOptimizer[lodDim.getWidth()][lodDim.getWidth()];
// this will be the center of the VBOs once they have been built // this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos; buildableCenterChunkPos = playerChunkPos;
@@ -260,7 +265,10 @@ public class LodBufferBuilderFactory
// make sure the buffers weren't // make sure the buffers weren't
// changed while we were running this method // changed while we were running this method
if (currentBuffers == null || !currentBuffers[0].building()) if (currentBuffers == null || !currentBuffers[0].building())
{
ClientApi.LOGGER.info("Buffer building quit early");
return; return;
}
byte minDetail = region.getMinDetailLevel(); byte minDetail = region.getMinDetailLevel();
@@ -280,14 +288,16 @@ public class LodBufferBuilderFactory
int bufferIndex; int bufferIndex;
boolean posNotInPlayerChunk; boolean posNotInPlayerChunk;
boolean adjPosInPlayerChunk; boolean adjPosInPlayerChunk;
Box box = ThreadMapUtil.getBox(); VertexOptimizer vertexOptimizer = ThreadMapUtil.getBox();
boolean[] adjShadeDisabled = ThreadMapUtil.getAdjShadeDisabledArray(); boolean[] adjShadeDisabled = ThreadMapUtil.getAdjShadeDisabledArray();
// determine how many LODs we can stack vertically // determine how many LODs we can stack vertically
int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte) 0); int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte) 0);
//we get or create the map that will contain the adj data //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 //previous setToRender cache
if (setsToRender[xR][zR] == null) if (setsToRender[xR][zR] == null)
@@ -342,12 +352,14 @@ public class LodBufferBuilderFactory
Arrays.fill(adjShadeDisabled, false); Arrays.fill(adjShadeDisabled, false);
//We check every adj block in each direction //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; xAdj = posX + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).x;
zAdj = posZ + Box.DIRECTION_NORMAL_MAP.get(lodDirection).z; zAdj = posZ + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).z;
long data; int color;
int data;
byte flags;
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.getX(); chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.getX();
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.getZ(); chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.getZ();
adjPosInPlayerChunk = (chunkXdist == 0 && chunkZdist == 0); adjPosInPlayerChunk = (chunkXdist == 0 && chunkZdist == 0);
@@ -364,21 +376,25 @@ public class LodBufferBuilderFactory
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++) for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++)
{ {
data = lodDim.getData(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; adjData.get(lodDirection)[verticalIndex] = data;
adjFlags.get(lodDirection)[verticalIndex] = flags;
} }
} }
else else
{ {
//Otherwise, we check if this position is //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)) 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 render every vertical lod present in this position
// We only stop when we find a block that is void or non-existing block // 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++) for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++)
{ {
//we get the above block as adj UP //we get the above block as adj UP
if (verticalIndex > 0) if (verticalIndex > 0)
{
adjData.get(LodDirection.UP)[0] = lodDim.getData(detailLevel, posX, posZ, verticalIndex - 1); 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 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 //we get the below block as adj DOWN
if (verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ) - 1) if (verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ) - 1)
{
adjData.get(LodDirection.DOWN)[0] = lodDim.getData(detailLevel, posX, posZ, verticalIndex + 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 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 //We extract the data to render
color = lodDim.getColor(detailLevel, posX, posZ, verticalIndex);
data = lodDim.getData(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 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; break;
//We send the call to create the vertices //We send the call to create the vertices
CONFIG.client().graphics().advancedGraphics().getLodTemplate().template.addLodToBuffer(currentBuffers[bufferIndex], playerBlockPosRounded, data, adjData, CONFIG.client().graphics().advancedGraphics().getLodTemplate().template.addLodToBuffer(currentBuffers[bufferIndex], playerBlockPosRounded, color, data, flags, adjData, adjFlags,
detailLevel, posX, posZ, box, renderer.previousDebugMode, adjShadeDisabled); detailLevel, posX, posZ, vertexOptimizer, renderer.previousDebugMode, adjShadeDisabled);
} }
} // for pos to in list to render } // for pos to in list to render
// the thread executed successfully // the thread executed successfully
return true; return true;
}; };
nodeToRenderThreads.add(dataToRenderThread); nodeToRenderThreads.add(dataToRenderThread);
} }
} // region z } // region z
} // region z } // region z
@@ -458,13 +487,13 @@ public class LodBufferBuilderFactory
e.printStackTrace(); e.printStackTrace();
} }
finally finally
{
try
{ {
// clean up any potentially open resources // clean up any potentially open resources
if (buildableBuffers != null) if (buildableBuffers != null)
closeBuffers(fullRegen, lodDim); closeBuffers(fullRegen, lodDim);
try
{
// upload the new buffers // upload the new buffers
uploadBuffers(fullRegen, lodDim); uploadBuffers(fullRegen, lodDim);
} }
@@ -523,8 +552,11 @@ public class LodBufferBuilderFactory
* May have to wait for the bufferLock to open. * May have to wait for the bufferLock to open.
*/ */
public void setupBuffers(LodDimension lodDimension) public void setupBuffers(LodDimension lodDimension)
{
try
{ {
bufferLock.lock(); bufferLock.lock();
int numbRegionsWide = lodDimension.getWidth(); int numbRegionsWide = lodDimension.getWidth();
long regionMemoryRequired; long regionMemoryRequired;
int numberOfBuffers; int numberOfBuffers;
@@ -625,8 +657,17 @@ public class LodBufferBuilderFactory
} }
glProxy.setGlContext(oldContext); 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(); bufferLock.unlock();
} }
}
@@ -637,6 +678,8 @@ public class LodBufferBuilderFactory
* May have to wait for the bufferLock to open. * May have to wait for the bufferLock to open.
*/ */
public void destroyBuffers() public void destroyBuffers()
{
try
{ {
bufferLock.lock(); bufferLock.lock();
@@ -715,9 +758,17 @@ public class LodBufferBuilderFactory
// these don't contain any OpenGL objects, so // these don't contain any OpenGL objects, so
// they don't require any special clean-up // they don't require any special clean-up
buildableBuffers = null; 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(); bufferLock.unlock();
} }
}
/** Calls begin on each of the buildable BufferBuilders. */ /** Calls begin on each of the buildable BufferBuilders. */
private void startBuffers(boolean fullRegen, LodDimension lodDim) private void startBuffers(boolean fullRegen, LodDimension lodDim)
@@ -976,6 +1027,8 @@ public class LodBufferBuilderFactory
// don't wait for the lock to open, // don't wait for the lock to open,
// since this is called on the main render thread // since this is called on the main render thread
if (bufferLock.tryLock()) if (bufferLock.tryLock())
{
try
{ {
LodVertexBuffer[][][] tmpVbo = drawableVbos; LodVertexBuffer[][][] tmpVbo = drawableVbos;
drawableVbos = buildableVbos; drawableVbos = buildableVbos;
@@ -989,8 +1042,17 @@ public class LodBufferBuilderFactory
// the vbos have been swapped // the vbos have been swapped
switchVbos = false; 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(); bufferLock.unlock();
} }
}
return new VertexBuffersAndOffset(drawableVbos, drawableStorageBufferIds, drawableCenterChunkPos); 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.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode; 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.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
@@ -37,8 +37,8 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public abstract class AbstractLodTemplate public abstract class AbstractLodTemplate
{ {
/** Uploads the given LOD to the buffer. */ /** Uploads the given LOD to the buffer. */
public abstract void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData, 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, Box box, DebugMode debugging, boolean[] adjShadeDisabled); byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled);
/** add the given position and color to the buffer */ /** add the given position and color to the buffer */
protected void addPosAndColor(LodBufferBuilder 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.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode; 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.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil; import com.seibel.lod.core.util.DataPointUtil;
@@ -44,43 +44,43 @@ public class CubicLodTemplate extends AbstractLodTemplate
} }
@Override @Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData, public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled) 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; return;
// equivalent to 2^detailLevel // equivalent to 2^detailLevel
int blockWidth = 1 << detailLevel; int blockWidth = 1 << detailLevel;
int color;
if (debugging != DebugMode.OFF) if (debugging != DebugMode.OFF)
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB(); color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
else
color = DataPointUtil.getColor(data);
generateBoundingBox( generateBoundingBox(
box, vertexOptimizer,
DataPointUtil.getHeight(data), DataPointUtil.getHeight(data),
DataPointUtil.getDepth(data), DataPointUtil.getDepth(data),
blockWidth, blockWidth,
posX * blockWidth, 0, posZ * blockWidth, // x, y, z offset posX * blockWidth, 0, posZ * blockWidth, // x, y, z offset
bufferCenterBlockPos, bufferCenterBlockPos,
adjData, adjData,
adjFlags,
color, color,
DataPointUtil.getLightSkyAlt(data), DataPointUtil.getLightSkyAlt(data, flags),
DataPointUtil.getLightBlock(data), DataPointUtil.getLightBlock(data),
adjShadeDisabled); adjShadeDisabled);
addBoundingBoxToBuffer(buffer, box); addBoundingBoxToBuffer(buffer, vertexOptimizer);
} }
private void generateBoundingBox(Box box, private void generateBoundingBox(VertexOptimizer vertexOptimizer,
int height, int depth, int width, int height, int depth, int width,
double xOffset, double yOffset, double zOffset, double xOffset, double yOffset, double zOffset,
AbstractBlockPosWrapper bufferCenterBlockPos, AbstractBlockPosWrapper bufferCenterBlockPos,
Map<LodDirection, long[]> adjData, Map<LodDirection, int[]> adjData,
Map<LodDirection, byte[]> adjFlags,
int color, int color,
int skyLight, int skyLight,
int blockLight, int blockLight,
@@ -100,38 +100,38 @@ public class CubicLodTemplate extends AbstractLodTemplate
// which only uses floats // which only uses floats
double x = -bufferCenterBlockPos.getX(); double x = -bufferCenterBlockPos.getX();
double z = -bufferCenterBlockPos.getZ(); double z = -bufferCenterBlockPos.getZ();
box.reset(); vertexOptimizer.reset();
box.setColor(color, adjShadeDisabled); vertexOptimizer.setColor(color, adjShadeDisabled);
box.setLights(skyLight, blockLight); vertexOptimizer.setLights(skyLight, blockLight);
box.setWidth(width, height - depth, width); vertexOptimizer.setWidth(width, height - depth, width);
box.setOffset((int) (xOffset + x), (int) (depth + yOffset), (int) (zOffset + z)); vertexOptimizer.setOffset((int) (xOffset + x), (int) (depth + yOffset), (int) (zOffset + z));
box.setUpCulling(32, bufferCenterBlockPos); vertexOptimizer.setUpCulling(32, bufferCenterBlockPos);
box.setAdjData(adjData); vertexOptimizer.setAdjData(adjData, adjFlags);
} }
private void addBoundingBoxToBuffer(LodBufferBuilder buffer, Box box) private void addBoundingBoxToBuffer(LodBufferBuilder buffer, VertexOptimizer vertexOptimizer)
{ {
int color; int color;
int skyLight; int skyLight;
int blockLight; int blockLight;
for (LodDirection lodDirection : Box.DIRECTIONS) for (LodDirection lodDirection : VertexOptimizer.DIRECTIONS)
{ {
if(box.isCulled(lodDirection)) if(vertexOptimizer.isCulled(lodDirection))
continue; continue;
int verticalFaceIndex = 0; int verticalFaceIndex = 0;
while (box.shouldRenderFace(lodDirection, verticalFaceIndex)) while (vertexOptimizer.shouldRenderFace(lodDirection, verticalFaceIndex))
{ {
for (int vertexIndex = 0; vertexIndex < 6; vertexIndex++) for (int vertexIndex = 0; vertexIndex < 6; vertexIndex++)
{ {
color = box.getColor(lodDirection); color = vertexOptimizer.getColor(lodDirection);
skyLight = box.getSkyLight(lodDirection, verticalFaceIndex); skyLight = vertexOptimizer.getSkyLight(lodDirection, verticalFaceIndex);
blockLight = box.getBlockLight(); blockLight = vertexOptimizer.getBlockLight();
color = ColorUtil.applyLightValue(color, skyLight, blockLight); color = ColorUtil.applyLightValue(color, skyLight, blockLight);
addPosAndColor(buffer, addPosAndColor(buffer,
box.getX(lodDirection, vertexIndex), vertexOptimizer.getX(lodDirection, vertexIndex),
box.getY(lodDirection, vertexIndex, verticalFaceIndex) + DataPointUtil.VERTICAL_OFFSET, vertexOptimizer.getY(lodDirection, vertexIndex, verticalFaceIndex) + DataPointUtil.VERTICAL_OFFSET,
box.getZ(lodDirection, vertexIndex), vertexOptimizer.getZ(lodDirection, vertexIndex),
color); color);
} }
verticalFaceIndex++; verticalFaceIndex++;
@@ -24,7 +24,7 @@ import java.util.Map;
import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.LodDirection; import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode; 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.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; 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 public class DynamicLodTemplate extends AbstractLodTemplate
{ {
@Override @Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData, public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled) 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!"); 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.api.ClientApi;
import com.seibel.lod.core.enums.LodDirection; import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode; 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.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; 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 public class TriangularLodTemplate extends AbstractLodTemplate
{ {
@Override @Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData, public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled) 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!"); ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
} }
@@ -195,29 +195,13 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
startX = detail.startX[i]; startX = detail.startX[i];
startZ = detail.startZ[i]; startZ = detail.startZ[i];
long[] data; // creates a vertical DataPoint
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.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.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 // equivalent to 2^detailLevel
int size = 1 << detail.detailLevel; int size = 1 << detail.detailLevel;
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(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; int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
AbstractChunkPosWrapper chunkPos = chunk.getPos(); AbstractChunkPosWrapper chunkPos = chunk.getPos();
@@ -227,7 +211,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
int light; int light;
int lightSky; int lightSky;
int lightBlock; int lightBlock;
int generation = config.distanceGenerationMode.complexity; byte generation = config.distanceGenerationMode.complexity;
int xRel; int xRel;
int zRel; int zRel;
@@ -259,7 +243,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
if (height == DEFAULT_HEIGHT) if (height == DEFAULT_HEIGHT)
{ {
if (topBlock) if (topBlock)
dataToMerge[index * verticalData] = DataPointUtil.createVoidDataPoint(generation); dataToMergeFlags[index * verticalData] = DataPointUtil.createVoidDataPoint(generation);
break; break;
} }
@@ -284,14 +268,32 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
lightBlock = light & 0b1111; lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111; lightSky = (light >> 4) & 0b1111;
isDefault = ((light >> 8)) == 1; 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;
dataToMerge[index * verticalData + count] = DataPointUtil.createDataPoint(height - DataPointUtil.VERTICAL_OFFSET, depth - DataPointUtil.VERTICAL_OFFSET, color, lightSky, lightBlock, generation, isDefault);
topBlock = false; topBlock = false;
yAbs = depth - 1; yAbs = depth - 1;
count++; count++;
} }
} }
return dataToMerge;
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 (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, mergedColor, mergedData, mergedFlags, false);
}
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().getX(), chunk.getPos().getZ());
} }
/** /**
@@ -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.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@@ -78,7 +77,7 @@ public class LodDimensionFileHandler
* file handler, older versions (smaller numbers) will be deleted and overwritten, * file handler, older versions (smaller numbers) will be deleted and overwritten,
* newer versions (larger numbers) will be ignored and won't be read. * 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 * Allow saving asynchronously, but never try to save multiple regions
@@ -208,14 +207,14 @@ public class LodDimensionFileHandler
break; break;
} }
else if (fileVersion == 6) else if (fileVersion < LOD_SAVE_FILE_VERSION)
{ {
//this is old, but readable version //this is old, but readable version
byte[] data = ThreadMapUtil.getSaveContainer(tempDetailLevel); byte[] data = ThreadMapUtil.getSaveContainer(tempDetailLevel);
inputStream.read(data); inputStream.read(data);
inputStream.close(); inputStream.close();
// add the data to our region // add the data to our region
region.addLevelContainer(new VerticalLevelContainer(data, 6)); region.addLevelContainer(new VerticalLevelContainer(data, fileVersion));
} else } else
{ {
// this file is a readable version, // 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; 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 * @author Leonardo Amato
* @version 10-2-2021 * @version 10-2-2021
*/ */
public class Box public class VertexOptimizer
{ {
private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class); private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class);
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
@@ -207,7 +206,7 @@ public class Box
/** creates an empty box */ /** creates an empty box */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public Box() public VertexOptimizer()
{ {
boxOffset = new int[3]; boxOffset = new int[3];
boxWidth = 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 * 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 * @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 height;
int depth; int depth;
int minY = getMinY(); int minY = getMinY();
int maxY = getMaxY(); int maxY = getMaxY();
long singleAdjDataPoint; int singleAdjData;
byte singleAdjFlags;
/* TODO implement attached vertical face culling /* TODO implement attached vertical face culling
//Up direction case //Up direction case
if(DataPointUtil.doesItExist(adjData.get(Direction.UP))) if(DataPointUtil.doesItExist(adjData.get(Direction.UP)))
{ {
height = DataPointUtil.getHeight(singleAdjDataPoint); height = DataPointUtil.getHeight(singleAdjData);
depth = DataPointUtil.getDepth(singleAdjDataPoint); depth = DataPointUtil.getDepth(singleAdjData);
}*/ }*/
//Down direction case //Down direction case
singleAdjDataPoint = adjData.get(LodDirection.DOWN)[0]; singleAdjData = adjData.get(LodDirection.DOWN)[0];
if(DataPointUtil.doesItExist(singleAdjDataPoint)) singleAdjFlags = adjFlags.get(LodDirection.DOWN)[0];
skyLights.get(LodDirection.DOWN)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); if(DataPointUtil.doesItExist(singleAdjFlags))
skyLights.get(LodDirection.DOWN)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
else else
skyLights.get(LodDirection.DOWN)[0] = skyLights.get(LodDirection.UP)[0]; skyLights.get(LodDirection.DOWN)[0] = skyLights.get(LodDirection.UP)[0];
//other sided //other sided
@@ -367,8 +368,9 @@ public class Box
if (isCulled(lodDirection)) if (isCulled(lodDirection))
continue; continue;
long[] dataPoint = adjData.get(lodDirection); int[] data = adjData.get(lodDirection);
if (dataPoint == null || DataPointUtil.isVoid(dataPoint[0])) byte[] flags = adjFlags.get(lodDirection);
if (DataPointUtil.isVoid(flags[0]))
{ {
adjHeight.get(lodDirection)[0] = maxY; adjHeight.get(lodDirection)[0] = maxY;
adjDepth.get(lodDirection)[0] = minY; adjDepth.get(lodDirection)[0] = minY;
@@ -384,15 +386,16 @@ public class Box
boolean toFinish = false; boolean toFinish = false;
int toFinishIndex = 0; int toFinishIndex = 0;
boolean allAbove = true; 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; break;
height = DataPointUtil.getHeight(singleAdjDataPoint); height = DataPointUtil.getHeight(singleAdjData);
depth = DataPointUtil.getDepth(singleAdjDataPoint); depth = DataPointUtil.getDepth(singleAdjData);
if (depth <= maxY) if (depth <= maxY)
{ {
@@ -405,12 +408,12 @@ public class Box
{ {
adjHeight.get(lodDirection)[0] = getMaxY(); adjHeight.get(lodDirection)[0] = getMaxY();
adjDepth.get(lodDirection)[0] = getMinY(); 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 else
{ {
adjDepth.get(lodDirection)[faceToDraw] = getMinY(); adjDepth.get(lodDirection)[faceToDraw] = getMinY();
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
} }
faceToDraw++; faceToDraw++;
toFinish = false; toFinish = false;
@@ -436,12 +439,12 @@ public class Box
{ {
adjHeight.get(lodDirection)[0] = getMaxY(); adjHeight.get(lodDirection)[0] = getMaxY();
adjDepth.get(lodDirection)[0] = height; 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 else
{ {
adjDepth.get(lodDirection)[faceToDraw] = height; adjDepth.get(lodDirection)[faceToDraw] = height;
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
} }
toFinish = false; toFinish = false;
faceToDraw++; faceToDraw++;
@@ -453,7 +456,7 @@ public class Box
// the adj data intersects the higher part of the current data // the adj data intersects the higher part of the current data
// we start the creation of a new face // we start the creation of a new face
adjHeight.get(lodDirection)[faceToDraw] = depth; adjHeight.get(lodDirection)[faceToDraw] = depth;
//skyLights.get(direction)[faceToDraw] = (byte) DataPointUtil.getLightSkyAlt(singleAdjDataPoint); //skyLights.get(direction)[faceToDraw] = (byte) DataPointUtil.getLightSkyAlt(singleAdjData);
firstFace = false; firstFace = false;
toFinish = true; toFinish = true;
toFinishIndex = i + 1; toFinishIndex = i + 1;
@@ -469,7 +472,7 @@ public class Box
} }
adjDepth.get(lodDirection)[faceToDraw] = height; adjDepth.get(lodDirection)[faceToDraw] = height;
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
faceToDraw++; faceToDraw++;
adjHeight.get(lodDirection)[faceToDraw] = depth; adjHeight.get(lodDirection)[faceToDraw] = depth;
firstFace = false; firstFace = false;
@@ -489,11 +492,12 @@ public class Box
else if (toFinish) else if (toFinish)
{ {
adjDepth.get(lodDirection)[faceToDraw] = minY; adjDepth.get(lodDirection)[faceToDraw] = minY;
if(toFinishIndex < dataPoint.length) if(toFinishIndex < flags.length)
{ {
singleAdjDataPoint = dataPoint[toFinishIndex]; singleAdjData = data[toFinishIndex];
if (DataPointUtil.doesItExist(singleAdjDataPoint)) singleAdjFlags = flags[toFinishIndex];
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); if (DataPointUtil.doesItExist(singleAdjFlags))
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
else else
skyLights.get(lodDirection)[faceToDraw] = skyLights.get(LodDirection.UP)[0]; skyLights.get(lodDirection)[faceToDraw] = skyLights.get(LodDirection.UP)[0];
} }
@@ -32,7 +32,7 @@ public interface LevelContainer
* @param index z position in the detail level * @param index z position in the detail level
* @return true if correctly added, false otherwise * @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 * 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 * @param posZ z position in the detail level
* @return true if correctly added, false otherwise * @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 * 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 * @param posZ z position in the detail level
* @return true if correctly added, false otherwise * @return true if correctly added, false otherwise
*/ */
boolean addSingleData(long data, int posX, int posZ); boolean addSingleData(int color, int data, byte flags, int posX, int posZ);
/** int getColor(int posX, int posZ, int verticalIndex);
* With this you can get data from the level container
* @param posX x position in the detail level int getData(int posX, int posZ, int index);
* @param posZ z position in the detail level
* @return the data in long array format byte getFlags(int posX, int posZ, int index);
*/
long getData(int posX, int posZ, int index); byte getSingleFlags(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 getSingleData(int posX, int posZ);
/** /**
* data is returned to ThreadMapUtil variables
* @param posX x position in the detail level * @param posX x position in the detail level
* @param posZ z position in the detail level * @param posZ z position in the detail level
* @return true only if the data exist * @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.handlers.LodDimensionFileHandler;
import com.seibel.lod.core.objects.PosToGenerateContainer; import com.seibel.lod.core.objects.PosToGenerateContainer;
import com.seibel.lod.core.objects.PosToRenderContainer; import com.seibel.lod.core.objects.PosToRenderContainer;
import com.seibel.lod.core.util.DataPointUtil; import com.seibel.lod.core.util.*;
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.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; 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 * stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten. * 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 regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ); int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -455,7 +450,7 @@ public class LodDimension
if (region == null) if (region == null)
return false; 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 // only save valid LODs to disk
if (!dontSave && fileHandler != null) if (!dontSave && fileHandler != null)
@@ -487,7 +482,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given * stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten. * 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 regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ); int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -497,7 +492,7 @@ public class LodDimension
if (region == null) if (region == null)
return false; 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 // only save valid LODs to disk
if (!dontSave && fileHandler != null) if (!dontSave && fileHandler != null)
@@ -566,7 +561,9 @@ public class LodDimension
byte detailLevel; byte detailLevel;
int posX; int posX;
int posZ; int posZ;
long data; int color;
int data;
byte flags;
int numbChunksWide = (width) * 32; int numbChunksWide = (width) * 32;
int circleLimit = Integer.MAX_VALUE; int circleLimit = Integer.MAX_VALUE;
@@ -614,11 +611,11 @@ public class LodDimension
posX = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, detailLevel); posX = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, detailLevel);
posZ = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, zChunkToCheck, 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. //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 //an un-generated area will always have 0 generation
if (DataPointUtil.getGenerationMode(data) < complexity) if (DataPointUtil.getGenerationMode(flags) < complexity)
{ {
posToGenerate.addPosToGenerate(detailLevel, posX, posZ); posToGenerate.addPosToGenerate(detailLevel, posX, posZ);
if (maxDataToGenerate >= 0) if (maxDataToGenerate >= 0)
@@ -705,43 +702,52 @@ public class LodDimension
return region.getMaxVerticalData(detailLevel); return region.getMaxVerticalData(detailLevel);
} }
/** public int getColor(byte detailLevel, int posX, int posZ, int 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 getData(byte detailLevel, int posX, int posZ, int verticalIndex)
{ {
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL) if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max."); throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ); LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null) if (region == null)
return DataPointUtil.EMPTY_DATA; return 0;
else
return region.getColor(detailLevel, posX, posZ, verticalIndex);
}
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 0;
else
return region.getData(detailLevel, posX, posZ, verticalIndex); return region.getData(detailLevel, posX, posZ, verticalIndex);
} }
public byte getFlags(byte detailLevel, int posX, int posZ, int 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)
{ {
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL) if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max."); throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ); LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null) if (region == null)
return DataPointUtil.EMPTY_DATA; return 0;
else
return region.getFlags(detailLevel, posX, posZ, verticalIndex);
}
return region.getSingleData(detailLevel, posX, posZ); 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 */ /** Clears the given region */
@@ -154,7 +154,7 @@ public class LodRegion
* TODO this will always return true unless it has * TODO this will always return true unless it has
* @return true if the data was added successfully * @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); posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
@@ -166,7 +166,7 @@ public class LodRegion
this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel); 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; return true;
} }
@@ -177,7 +177,7 @@ public class LodRegion
* TODO this will always return true unless it has * TODO this will always return true unless it has
* @return true if the data was added successfully * @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 //position is already relative
//posX = LevelPosUtil.getRegionModule(detailLevel, posX); //posX = LevelPosUtil.getRegionModule(detailLevel, posX);
@@ -188,29 +188,35 @@ public class LodRegion
if (this.dataContainer[detailLevel] == null) if (this.dataContainer[detailLevel] == null)
this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel); this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
return this.dataContainer[detailLevel].addVerticalData(data, posX, posZ); return this.dataContainer[detailLevel].addVerticalData(color, data, flags, posX, posZ);
} }
/** public int getColor(byte detailLevel, int posX, int posZ, int verticalIndex)
* Get the dataPoint at the given relative position. {
* @return the data at the relative pos and detail level, return dataContainer[detailLevel].getColor(posX, posZ, verticalIndex);
* 0 if the data doesn't exist. }
*/
public long getData(byte detailLevel, int posX, int posZ, int verticalIndex) public int getData(byte detailLevel, int posX, int posZ, int verticalIndex)
{ {
return dataContainer[detailLevel].getData(posX, posZ, 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, * @return the data at the relative pos and detail level,
* 0 if the data doesn't exist. * 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 * Clears the datapoint at the given relative position
*/ */
@@ -358,6 +364,7 @@ public class LodRegion
posZ + regionPosZ * size); posZ + regionPosZ * size);
} }
else else
{
//if (desiredLevel > detailLevel) //if (desiredLevel > detailLevel)
//{ //{
// we have gone beyond the target Detail level // we have gone beyond the target Detail level
@@ -409,6 +416,7 @@ public class LodRegion
} }
} }
} }
}
/** /**
@@ -479,7 +487,7 @@ public class LodRegion
if (dataContainer[detailLevel].doesItExist(posX, posZ)) if (dataContainer[detailLevel].doesItExist(posX, posZ))
// We take the bottom information always // We take the bottom information always
// TODO what does that mean? bottom of what? // 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 else
return DistanceGenerationMode.NONE.complexity; return DistanceGenerationMode.NONE.complexity;
} }
@@ -37,14 +37,19 @@ public class VerticalLevelContainer implements LevelContainer
public final int size; public final int size;
public final int maxVerticalData; public final int maxVerticalData;
public final long[] dataContainer; public final int[] dataContainerColor;
public final int[] dataContainerData;
public final byte[] dataContainerFlags;
public VerticalLevelContainer(byte detailLevel) public VerticalLevelContainer(byte detailLevel)
{ {
this.detailLevel = detailLevel; this.detailLevel = detailLevel;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
maxVerticalData = DetailDistanceUtil.getMaxVerticalData(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 @Override
@@ -60,47 +65,77 @@ public class VerticalLevelContainer implements LevelContainer
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++) 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 @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); posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); 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; return true;
} }
@Override @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); posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++) 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; return true;
} }
@Override @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 @Override
public long getData(int posX, int posZ, int verticalIndex) public int getColor(int posX, int posZ, int verticalIndex)
{ {
posX = LevelPosUtil.getRegionModule(detailLevel, posX); posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); 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 @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 @Override
@@ -119,7 +154,7 @@ public class VerticalLevelContainer implements LevelContainer
{ {
posX = LevelPosUtil.getRegionModule(detailLevel, posX); posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); 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) public VerticalLevelContainer(byte[] inputData, int version)
@@ -127,69 +162,131 @@ public class VerticalLevelContainer implements LevelContainer
int tempMaxVerticalData; int tempMaxVerticalData;
int tempIndex; int tempIndex;
int index = 0; int index = 0;
long newData;
detailLevel = inputData[index]; detailLevel = inputData[index];
index++; index++;
tempMaxVerticalData = inputData[index] & 0b01111111; tempMaxVerticalData = inputData[index] & 0b01111111;
index++; index++;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int x = size * size * tempMaxVerticalData; 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) if (version == 6)
{ {
long oldData;
for (int i = 0; i < x; i++) for (int i = 0; i < x; i++)
{ {
newData = 0; oldData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++) for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex); oldData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
/*
|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
);
tempDataContainerColor[i] = ThreadMapUtil.dataPointColor;
tempDataContainerData[i] = ThreadMapUtil.dataPointData;
tempDataContainerFlags[i] = ThreadMapUtil.dataPointFlags;
}
}
else if (version == 7)
{
long oldData;
for (int i = 0; i < x; i++)
{
oldData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++)
oldData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
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; index += 8;
newData = DataPointUtil.createDataPoint( tempDataContainerColor[i] = color;
DataPointUtil.getAlpha(newData), tempDataContainerData[i] = data;
DataPointUtil.getRed(newData), tempDataContainerFlags[i] = flags;
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)
);
tempDataContainer[i] = newData;
}
}
else //if (version == 7)
{
for (int i = 0; i < x; i++)
{
newData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
tempDataContainer[i] = newData;
} }
} }
if (tempMaxVerticalData > DetailDistanceUtil.getMaxVerticalData(detailLevel)) if (tempMaxVerticalData > DetailDistanceUtil.getMaxVerticalData(detailLevel))
{ {
int tempMaxVerticalData2 = DetailDistanceUtil.getMaxVerticalData(detailLevel); int tempMaxVerticalData2 = DetailDistanceUtil.getMaxVerticalData(detailLevel);
long[] dataToMerge = new long[tempMaxVerticalData]; int[] dataToMergeColor = new int[tempMaxVerticalData];
long[] tempDataContainer2 = new long[size * size * tempMaxVerticalData2]; 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++) for (int i = 0; i < size * size; i++)
{ {
System.arraycopy(tempDataContainer, i * tempMaxVerticalData, dataToMerge, 0, tempMaxVerticalData); System.arraycopy(tempDataContainerColor, i * tempMaxVerticalData, dataToMergeColor, 0, tempMaxVerticalData);
dataToMerge = DataPointUtil.mergeMultiData(dataToMerge, tempMaxVerticalData, tempMaxVerticalData2); System.arraycopy(tempDataContainerData, i * tempMaxVerticalData, dataToMergeData, 0, tempMaxVerticalData);
System.arraycopy(dataToMerge, 0, tempDataContainer2, i * tempMaxVerticalData2, tempMaxVerticalData2); 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; maxVerticalData = tempMaxVerticalData2;
this.dataContainer = tempDataContainer2; this.dataContainerColor = tempDataContainer2Color;
this.dataContainerData = tempDataContainer2Data;
this.dataContainerFlags = tempDataContainer2Flags;
} }
else else
{ {
maxVerticalData = tempMaxVerticalData; 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) public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{ {
//We reset the array //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 childPosX;
int childPosZ; int childPosZ;
long[] data;
posX = LevelPosUtil.getRegionModule(detailLevel, posX); posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++) for (int x = 0; x <= 1; x++)
@@ -218,12 +316,17 @@ public class VerticalLevelContainer implements LevelContainer
childPosX = 2 * posX + x; childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z; childPosZ = 2 * posZ + z;
for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++) for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++)
dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex); {
}
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData());
addVerticalData(data, posX, posZ); 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);
}
}
}
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, lowerMaxVertical, getMaxVerticalData());
addVerticalData(ThreadMapUtil.getRawVerticalDataArrayColor(), ThreadMapUtil.getRawVerticalDataArrayData(), ThreadMapUtil.getRawVerticalDataArrayFlags(), posX, posZ);
} }
@Override @Override
@@ -232,7 +335,8 @@ public class VerticalLevelContainer implements LevelContainer
int index = 0; int index = 0;
int x = size * size; int x = size * size;
int tempIndex; int tempIndex;
long current; int currentColor;
int currentData;
boolean allGenerated = true; boolean allGenerated = true;
byte[] tempData = ThreadMapUtil.getSaveContainer(detailLevel); byte[] tempData = ThreadMapUtil.getSaveContainer(detailLevel);
@@ -245,12 +349,18 @@ public class VerticalLevelContainer implements LevelContainer
{ {
for (j = 0; j < maxVerticalData; j++) for (j = 0; j < maxVerticalData; j++)
{ {
current = dataContainer[i * maxVerticalData + j]; currentColor = dataContainerColor[i * maxVerticalData + j];
for (tempIndex = 0; tempIndex < 8; tempIndex++) currentData = dataContainerData[i * maxVerticalData + j];
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex)); 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; index += 8;
} }
if(!DataPointUtil.doesItExist(dataContainer[i])) if(!DataPointUtil.doesItExist(dataContainerFlags[i]))
allGenerated = false; allGenerated = false;
} }
if (allGenerated) if (allGenerated)
@@ -57,9 +57,9 @@ public class DataPointUtil
//To be used in the future for negative value //To be used in the future for negative value
//public final static int MIN_DEPTH = -64; //public final static int MIN_DEPTH = -64;
//public final static int MIN_HEIGHT = -64; //public final static int MIN_HEIGHT = -64;
public final static int EMPTY_DATA = 0; public final static byte EMPTY_DATA = 0;
public static final short VERTICAL_OFFSET = -64; public static final short VERTICAL_OFFSET = -2048;
public static int WORLD_HEIGHT = 1024; public static int WORLD_HEIGHT = 4096;
public final static int ALPHA_DOWNSIZE_SHIFT = 4; 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 RED_COLOR_SHIFT = 16;
//public final static int ALPHA_COLOR_SHIFT = 24; //public final static int ALPHA_COLOR_SHIFT = 24;
public final static int BLUE_SHIFT = 36; public final static byte BLUE_SHIFT = 0;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8; public final static byte GREEN_SHIFT = 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16; public final static byte RED_SHIFT = 16;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24; 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 byte HEIGHT_SHIFT = 20;
public final static int DEPTH_SHIFT = 16; public final static byte DEPTH_SHIFT = 8;
public final static int BLOCK_LIGHT_SHIFT = 12; public final static byte BLOCK_LIGHT_SHIFT = 4;
public final static int SKY_LIGHT_SHIFT = 8; public final static byte SKY_LIGHT_SHIFT = 0;
//public final static int LIGHTS_SHIFT = SKY_LIGHT_SHIFT; //public final static byte LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
//public final static int VERTICAL_INDEX_SHIFT = 6; //public final static byte VERTICAL_INDEX_SHIFT = 6;
public final static int FLAG_SHIFT = 5; public final static byte FLAG_SHIFT = 5;
public final static int GEN_TYPE_SHIFT = 2; public final static byte GEN_TYPE_SHIFT = 2;
public final static int VOID_SHIFT = 1; public final static byte VOID_SHIFT = 1;
public final static int EXISTENCE_SHIFT = 0; public final static byte EXISTENCE_SHIFT = 0;
public final static long ALPHA_MASK = 0b1111; public final static int ALPHA_MASK = 0xFF;
public final static long RED_MASK = 0b1111_1111; public final static int RED_MASK = 0xFF;
public final static long GREEN_MASK = 0b1111_1111; public final static int GREEN_MASK = 0xFF;
public final static long BLUE_MASK = 0b1111_1111; public final static int BLUE_MASK = 0xFF;
public final static long COLOR_MASK = 0b11111111_11111111_11111111; public final static int COLOR_MASK = 0xFFFFFFFF;
public final static long HEIGHT_MASK = 0b11_1111_1111; public final static int HEIGHT_MASK = 0xFFF;
public final static long DEPTH_MASK = 0b11_1111_1111; public final static int DEPTH_MASK = 0xFFF;
//public final static long LIGHTS_MASK = 0b1111_1111; public final static int LIGHTS_MASK = 0xFF;
public final static long BLOCK_LIGHT_MASK = 0b1111; public final static int BLOCK_LIGHT_MASK = 0xF;
public final static long SKY_LIGHT_MASK = 0b1111; public final static int SKY_LIGHT_MASK = 0xF;
//public final static long VERTICAL_INDEX_MASK = 0b11; public final static int VERTICAL_INDEX_MASK = 0x3;
public final static long FLAG_MASK = 0b1; public final static byte FLAG_MASK = 0x1;
public final static long GEN_TYPE_MASK = 0b111; public final static byte GEN_TYPE_MASK = 0x7;
public final static long VOID_MASK = 1; public final static byte VOID_MASK = 1;
public final static long EXISTENCE_MASK = 1; public final static byte EXISTENCE_MASK = 1;
/** Returns the Flags byte */
public static long createVoidDataPoint(int generationMode) public static byte createVoidDataPoint(byte generationMode)
{ {
long dataPoint = 0; generationMode = (byte) ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT);
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT; generationMode |= VOID_MASK << VOID_SHIFT;
dataPoint += VOID_MASK << VOID_SHIFT; generationMode |= EXISTENCE_MASK << EXISTENCE_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT; return generationMode;
return dataPoint;
} }
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( int data = (height & HEIGHT_MASK) << HEIGHT_SHIFT;
ColorUtil.getAlpha(color), data += (depth & DEPTH_MASK) << DEPTH_SHIFT;
ColorUtil.getRed(color), data += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
ColorUtil.getGreen(color), data += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
ColorUtil.getBlue(color), byte flags = (byte) ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT);
height, depth, lightSky, lightBlock, generationMode, flag); 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; createDataPoint(
dataPoint += (long) (alpha >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT; height, depth,
dataPoint += (red & RED_MASK) << RED_SHIFT; (alpha << ALPHA_SHIFT) | (red << RED_SHIFT) | (green << GREEN_SHIFT) | blue,
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT; lightSky, lightBlock, generationMode, flag);
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;
} }
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; return 0;
else 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(byte flags)
public static boolean isVoid(long dataPoint)
{ {
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) */ /** This is used to convert a dataPoint to string (useful for the print function) */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static String toString(long dataPoint) public static String toString(int color, int data, byte flags)
{ {
return getHeight(dataPoint) + " " + return getHeight(data) + " " +
getDepth(dataPoint) + " " + getDepth(data) + " " +
getAlpha(dataPoint) + " " + getAlpha(color) + " " +
getRed(dataPoint) + " " + getRed(color) + " " +
getBlue(dataPoint) + " " + getBlue(color) + " " +
getGreen(dataPoint) + " " + getGreen(color) + " " +
getLightBlock(dataPoint) + " " + getLightBlock(data) + " " +
getLightSky(dataPoint) + " " + getLightSky(data) + " " +
getGenerationMode(dataPoint) + " " + getGenerationMode(flags) + " " +
isVoid(dataPoint) + " " + isVoid(flags) + " " +
doesItExist(dataPoint) + '\n'; doesItExist(flags) + '\n';
} }
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize) 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 * 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 inputVerticalData vertical size of an input data
* @param maxVerticalData max vertical size of the merged 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 // We initialize the arrays that are going to be used
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((WORLD_HEIGHT / 2 + 1) * 2); 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 allEmpty = true;
boolean allVoid = true; boolean allVoid = true;
boolean allDefault; boolean allDefault;
long singleData; int singleDataData;
byte singleDataFlags;
short depth; short depth;
@@ -290,16 +287,17 @@ public class DataPointUtil
{ {
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++) for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{ {
singleData = dataToMerge[index * inputVerticalData + dataIndex]; singleDataData = dataToMergeData[index * inputVerticalData + dataIndex];
if (doesItExist(singleData)) singleDataFlags = dataToMergeFlags[index * inputVerticalData + dataIndex];
if (doesItExist(singleDataFlags))
{ {
genMode = Math.min(genMode, getGenerationMode(singleData)); genMode = (byte) Math.min(genMode, getGenerationMode(singleDataFlags));
allEmpty = false; allEmpty = false;
if (!isVoid(singleData)) if (!isVoid(singleDataFlags))
{ {
allVoid = false; allVoid = false;
depth = getDepth(singleData); depth = getDepth(singleDataData);
height = getHeight(singleData); height = getHeight(singleDataData);
int botPos = -1; int botPos = -1;
int topPos = -1; int topPos = -1;
@@ -402,11 +400,11 @@ public class DataPointUtil
//We check if there is any data that's not empty or void //We check if there is any data that's not empty or void
if (allEmpty) if (allEmpty)
return dataPoint; return;
if (allVoid) if (allVoid)
{ {
dataPoint[0] = createVoidDataPoint(genMode); dataPointFlags[0] = createVoidDataPoint(genMode);
return dataPoint; return;
} }
//we limit the vertical portion to maxVerticalData //we limit the vertical portion to maxVerticalData
@@ -451,59 +449,75 @@ public class DataPointUtil
allEmpty = true; allEmpty = true;
allVoid = true; allVoid = true;
allDefault = 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 (int index = 0; index < size; index++)
{ {
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++) for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{ {
singleData = dataToMerge[index * inputVerticalData + dataIndex]; singleDataColor = dataToMergeColor[index * inputVerticalData + dataIndex];
if (doesItExist(singleData) && !isVoid(singleData)) singleDataData = dataToMergeData[index * inputVerticalData + dataIndex];
singleDataFlags = dataToMergeFlags[index * inputVerticalData + dataIndex];
if (doesItExist(singleDataFlags) && !isVoid(singleDataFlags))
{ {
if ((depth <= getDepth(singleDataData) && getDepth(singleDataData) <= height)
if ((depth <= getDepth(singleData) && getDepth(singleData) <= height) || (depth <= getHeight(singleDataData) && getHeight(singleDataData) <= height))
|| (depth <= getHeight(singleData) && getHeight(singleData) <= height))
{ {
if (getHeight(singleData) > getHeight(data)) if (getHeight(singleDataData) > getHeight(data))
data = singleData; {
color = singleDataColor;
data = singleDataData;
flags = singleDataFlags;
}
} }
} }
else else
break; break;
} }
if (!doesItExist(data)) if (!doesItExist(flags))
{ {
singleData = dataToMerge[index * inputVerticalData]; singleDataFlags = dataToMergeFlags[index * inputVerticalData];
data = createVoidDataPoint(getGenerationMode(singleData)); 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; allEmpty = false;
if (!isVoid(data)) if (!isVoid(flags))
{ {
numberOfChildren++; numberOfChildren++;
allVoid = false; allVoid = false;
tempAlpha += getAlpha(data); tempAlpha += getAlpha(color);
tempRed += getRed(data); tempRed += getRed(color);
tempGreen += getGreen(data); tempGreen += getGreen(color);
tempBlue += getBlue(data); tempBlue += getBlue(color);
tempLightBlock += getLightBlock(data); tempLightBlock += getLightBlock(data);
tempLightSky += getLightSky(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 else
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity); tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
} }
if (allEmpty) if (!allEmpty)
//no child has been initialized {
dataPoint[j] = EMPTY_DATA; //child has been initialized
else if (allVoid) if (allVoid)
{
//all the children are void //all the children are void
dataPoint[j] = createVoidDataPoint(tempGenMode); dataPointFlags[j] = createVoidDataPoint(tempGenMode);
}
else else
{ {
//we have at least 1 child //we have at least 1 child
@@ -513,9 +527,12 @@ public class DataPointUtil
tempBlue = tempBlue / numberOfChildren; tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren; tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren; tempLightSky = tempLightSky / numberOfChildren;
dataPoint[j] = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault); 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 treeGenMultiplier = 1.0;
private static final double treeCutMultiplier = 1.0; private static final double treeCutMultiplier = 1.0;
private static byte minGenDetail = CONFIG.client().graphics().quality().getDrawResolution().detailLevel; 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 maxDetail = LodUtil.REGION_DETAIL_LEVEL + 1;
private static final int minDistance = 0; private static final int minDistance = 0;
private static int minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f); private static int minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f);
@@ -79,7 +79,7 @@ public class DetailDistanceUtil
if (CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality()) if (CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
return detail * 0x10000; //if you want more you are doing wrong 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) if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
return (detail * distanceUnit); return (detail * distanceUnit);
else else
@@ -96,14 +96,14 @@ public class DetailDistanceUtil
public static byte baseInverseFunction(int distance, byte minDetail, boolean useRenderMinDistance) public static byte baseInverseFunction(int distance, byte minDetail, boolean useRenderMinDistance)
{ {
int detail; byte detail;
if (distance == 0 if (distance == 0
|| (distance < minDetailDistance && useRenderMinDistance) || (distance < minDetailDistance && useRenderMinDistance)
|| CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality()) || CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
return minDetail; 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) if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
detail = (byte) distance / distanceUnit; detail = (byte) (distance / distanceUnit);
else else
{ {
double base = CONFIG.client().graphics().quality().getHorizontalQuality().quadraticBase; double base = CONFIG.client().graphics().quality().getHorizontalQuality().quadraticBase;
@@ -139,12 +139,12 @@ public class DetailDistanceUtil
return CONFIG.client().worldGenerator().getDistanceGenerationMode(); return CONFIG.client().worldGenerator().getDistanceGenerationMode();
} }
public static byte getLodDrawDetail(int detail) public static byte getLodDrawDetail(byte detail)
{ {
if (detail < minDrawDetail) detail += minDrawDetail;
return minDrawDetail; if (detail > 10)
else detail = 10;
return (byte) detail; return detail;
} }
public static HorizontalResolution getLodGenDetail(int 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.LodDirection;
import com.seibel.lod.core.enums.config.HorizontalResolution; import com.seibel.lod.core.enums.config.HorizontalResolution;
import com.seibel.lod.core.enums.config.VanillaOverdraw; 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.LodDimension;
import com.seibel.lod.core.objects.lod.RegionPos; import com.seibel.lod.core.objects.lod.RegionPos;
import com.seibel.lod.core.objects.opengl.DefaultLodVertexFormats; import com.seibel.lod.core.objects.opengl.DefaultLodVertexFormats;
@@ -403,10 +403,10 @@ public class LodUtil
return false; return false;
int tempX; int tempX;
int tempZ; int tempZ;
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS) for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
{ {
tempX = x + Box.DIRECTION_NORMAL_MAP.get(lodDirection).x; tempX = x + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).x;
tempZ = z + Box.DIRECTION_NORMAL_MAP.get(lodDirection).z; tempZ = z + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).z;
if (vanillaRenderedChunks[x][z] || (!(tempX < 0 || tempZ < 0 || tempX >= vanillaRenderedChunks.length || tempZ >= vanillaRenderedChunks[0].length) if (vanillaRenderedChunks[x][z] || (!(tempX < 0 || tempZ < 0 || tempX >= vanillaRenderedChunks.length || tempZ >= vanillaRenderedChunks[0].length)
&& !vanillaRenderedChunks[tempX][tempZ])) && !vanillaRenderedChunks[tempX][tempZ]))
return true; return true;
@@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import com.seibel.lod.core.enums.LodDirection; 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 * Holds data used by specific threads so
@@ -38,15 +38,18 @@ import com.seibel.lod.core.objects.Box;
*/ */
public class ThreadMapUtil public class ThreadMapUtil
{ {
public static final ConcurrentMap<String, long[]> threadSingleUpdateMap = new ConcurrentHashMap<>(); public static final ConcurrentMap<String, int[][]> threadBuilderVerticalArrayMapColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> threadBuilderArrayMap = new ConcurrentHashMap<>(); public static final ConcurrentMap<String, int[][]> threadBuilderVerticalArrayMapData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap<>(); public static final ConcurrentMap<String, byte[][]> threadBuilderVerticalArrayMapFlags = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadVerticalAddDataMap = 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, byte[][]> saveContainer = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, short[]> projectionArrayMap = 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, short[]> heightAndDepthMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap<>(); public static final ConcurrentMap<String, int[][]> verticalUpdateColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> verticalUpdate = 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, boolean[]> adjShadeDisabled = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, long[]>> adjDataMap = new ConcurrentHashMap<>(); public static final ConcurrentMap<String, Map<LodDirection, int[]>> adjDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Box> boxMap = 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()) if (!adjShadeDisabled.containsKey(Thread.currentThread().getName())
|| (adjShadeDisabled.get(Thread.currentThread().getName()) == null)) || (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); Arrays.fill(adjShadeDisabled.get(Thread.currentThread().getName()), false);
return adjShadeDisabled.get(Thread.currentThread().getName()); return adjShadeDisabled.get(Thread.currentThread().getName());
} }
/** returns the array NOT cleared every time */ /** 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()) if (!adjDataMap.containsKey(Thread.currentThread().getName())
|| (adjDataMap.get(Thread.currentThread().getName()) == null) || (adjDataMap.get(Thread.currentThread().getName()) == null)
@@ -80,26 +88,47 @@ public class ThreadMapUtil
|| (adjDataMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData)) || (adjDataMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData))
{ {
adjDataMap.put(Thread.currentThread().getName(), new HashMap<>()); 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.UP, new int[1]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new long[1]); adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new int[1]);
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS) for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new long[verticalData]); adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new int[verticalData]);
} }
else else
{ {
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
for (LodDirection lodDirection : Box.ADJ_DIRECTIONS) Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), 0);
Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), DataPointUtil.EMPTY_DATA);
} }
return adjDataMap.get(Thread.currentThread().getName()); 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()) if (!boxMap.containsKey(Thread.currentThread().getName())
|| (boxMap.get(Thread.currentThread().getName()) == null)) || (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(); boxMap.get(Thread.currentThread().getName()).reset();
return boxMap.get(Thread.currentThread().getName()); return boxMap.get(Thread.currentThread().getName());
@@ -119,21 +148,57 @@ public class ThreadMapUtil
/** returns the array filled with 0's */ /** 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; int size;
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
size = 1 << 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); Arrays.fill(threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel]; 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 */ /** returns the array NOT cleared every time */
@@ -145,7 +210,7 @@ public class ThreadMapUtil
int size = 1; int size = 1;
for (int i = LodUtil.DETAIL_OPTIONS - 1; i >= 0; i--) 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; size = size << 1;
} }
saveContainer.put(Thread.currentThread().getName(), array); saveContainer.put(Thread.currentThread().getName(), array);
@@ -156,19 +221,46 @@ public class ThreadMapUtil
/** returns the array filled with 0's */ /** 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)) if (!threadVerticalAddDataMapColor.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapColor.get(Thread.currentThread().getName()) == null))
{ threadVerticalAddDataMapColor.put(Thread.currentThread().getName(), new int[arrayLength]);
threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[arrayLength]);
}
else else
{ Arrays.fill(threadVerticalAddDataMapColor.get(Thread.currentThread().getName()), 0);
Arrays.fill(threadVerticalAddDataMap.get(Thread.currentThread().getName()), 0); return threadVerticalAddDataMapColor.get(Thread.currentThread().getName());
} }
return threadVerticalAddDataMap.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 */ /** returns the array NOT cleared every time */
@@ -181,22 +273,49 @@ public class ThreadMapUtil
return heightAndDepthMap.get(Thread.currentThread().getName()); return heightAndDepthMap.get(Thread.currentThread().getName());
} }
/** returns the array filled with 0's */ /** 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++) for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new long[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4]; array[i] = new int[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdate.put(Thread.currentThread().getName(), array); verticalUpdateColor.put(Thread.currentThread().getName(), array);
} }
else else
{ Arrays.fill(verticalUpdateColor.get(Thread.currentThread().getName())[detailLevel], 0);
Arrays.fill(verticalUpdate.get(Thread.currentThread().getName())[detailLevel], 0); return verticalUpdateColor.get(Thread.currentThread().getName())[detailLevel];
} }
return verticalUpdate.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))
{
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);
}
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 */ /** clears all arrays so they will have to be rebuilt */
@@ -205,14 +324,24 @@ public class ThreadMapUtil
adjShadeDisabled.clear(); adjShadeDisabled.clear();
adjDataMap.clear(); adjDataMap.clear();
boxMap.clear(); boxMap.clear();
threadSingleUpdateMap.clear(); threadBuilderVerticalArrayMapColor.clear();
threadBuilderArrayMap.clear(); threadBuilderVerticalArrayMapData.clear();
threadBuilderVerticalArrayMap.clear(); threadBuilderVerticalArrayMapFlags.clear();
threadVerticalAddDataMap.clear(); threadVerticalAddDataMapColor.clear();
threadVerticalAddDataMapData.clear();
threadVerticalAddDataMapFlags.clear();
saveContainer.clear(); saveContainer.clear();
projectionArrayMap.clear(); projectionArrayMap.clear();
heightAndDepthMap.clear(); heightAndDepthMap.clear();
singleDataToMergeMap.clear(); verticalUpdateColor.clear();
verticalUpdate.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; HorizontalResolution DRAW_RESOLUTION_DEFAULT = HorizontalResolution.BLOCK;
String DRAW_RESOLUTION_DESC = "" String DRAW_RESOLUTION_DESC = ""
+ " What is the maximum detail fake chunks should be drawn at? \n" + " 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" + " Higher settings will increase memory and GPU usage. \n"
+ "\n" + "\n"
+ " " + HorizontalResolution.CHUNK + ": render 1 LOD for each Chunk. \n" + " " + HorizontalResolution.CHUNK + ": render 1 LOD for each Chunk. \n"
@@ -111,20 +112,13 @@ public interface ILodConfigWrapperSingleton
VerticalQuality getVerticalQuality(); VerticalQuality getVerticalQuality();
void setVerticalQuality(VerticalQuality newVerticalQuality); 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 = "" String HORIZONTAL_SCALE_DESC = ""
+ " This indicates how quickly fake chunks decrease in quality the further away they are. \n" + " 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" + " Higher settings will render higher quality fake chunks farther away, \n"
+ " but will increase memory and GPU usage. \n" + " but will increase memory and GPU usage.";
+ "\n" int getHorizontalScale();
+ " " + HorizontalScale.LOW + ": quality drops every " + HorizontalScale.LOW.distanceUnit / 16 + " chunks. \n" void setHorizontalScale(int newHorizontalScale);
+ " " + 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);
HorizontalQuality HORIZONTAL_QUALITY_DEFAULT = HorizontalQuality.MEDIUM; HorizontalQuality HORIZONTAL_QUALITY_DEFAULT = HorizontalQuality.MEDIUM;
String HORIZONTAL_QUALITY_DESC = "" String HORIZONTAL_QUALITY_DESC = ""