Merge branch '1.16.5' of gitlab.com:jeseibel/minecraft-lod-mod into

1.16.5

# Conflicts:
#	src/main/java/com/seibel/lod/builders/LodBufferBuilder.java
This commit is contained in:
James Seibel
2021-09-14 23:46:01 -05:00
24 changed files with 1402 additions and 527 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ compileJava {
// release 8 is needed because otherwise FloatBuffer.flip() will crash
// on some machines
// example thread: https://github.com/eclipse/jetty.project/issues/3244
options.compilerArgs.addAll(['--release', '8', '-Xlint:unchecked', '-Xlint:deprecation'])
options.compilerArgs.addAll(['-Xlint:unchecked', '-Xlint:deprecation'])
}
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
+32
View File
@@ -0,0 +1,32 @@
package com.seibel.lod;
import com.google.common.primitives.UnsignedLong;
import com.seibel.lod.objects.PosToGenerateContainer;
import com.seibel.lod.util.DataPointUtil;
import javax.xml.crypto.Data;
import java.math.BigInteger;
public class Main
{
public static void main(String[] args)
{
/*
try
{
long[][] dataToMerge = new long[][]{
{DataPointUtil.createDataPoint(10, 5, 0, 0, 0)},
{DataPointUtil.createDataPoint(15, 5, 0, 0, 0)},
{DataPointUtil.createDataPoint(40, 20, 0, 0, 0)},
{DataPointUtil.createDataPoint(1, 0, 0, 0, 0)}};
long[] data = DataPointUtil.mergeVerticalData(dataToMerge);
for (long dataPoint : data)
{
System.out.println("depth " + DataPointUtil.getDepth(dataPoint));
System.out.println("height " + DataPointUtil.getHeight(dataPoint));
}
}catch (Exception e){
e.printStackTrace();
}*/
}
}
@@ -32,8 +32,6 @@ import org.lwjgl.opengl.GL15C;
import com.seibel.lod.builders.lodTemplates.Box;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.objects.LevelPosUtil;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.PosToRenderContainer;
@@ -42,10 +40,13 @@ import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.proxy.GlProxy;
import com.seibel.lod.proxy.GlProxy.GlProxyContext;
import com.seibel.lod.render.LodRenderer;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
@@ -117,8 +118,10 @@ public class LodBufferBuilder
private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center;
/** This is the ChunkPos the player was at the last time the buffers were built.
* IE the center of the buffers last time they were built */
/**
* This is the ChunkPos the player was at the last time the buffers were built.
* IE the center of the buffers last time they were built
*/
private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0, 0);
private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0, 0);
@@ -142,6 +145,20 @@ public class LodBufferBuilder
public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim,
BlockPos playerBlockPos, boolean fullRegen)
{
for(int i = 0; i<16; i++)
{
for(int j = 0; j<16; j++)
{
int lightTint = LightTexture.pack(i,j);
//System.out.print(ColorUtil.getRed(lightTint) + " " + ColorUtil.getGreen(lightTint) + " " + ColorUtil.getBlue(lightTint) + " ");
System.out.print(Integer.toHexString(lightTint) + " ");
}
System.out.println();
}
// only allow one generation process to happen at a time
if (generatingBuffers)
return;
@@ -246,8 +263,9 @@ public class LodBufferBuilder
int chunkXdist;
int chunkZdist;
short gameChunkRenderDistance = (short) (renderer.vanillaRenderedChunks.length / 2 - 1);
long dataPoint;
long[] adjData;
//long dataPoint;
long[] adjData = new long[NUMBER_OF_DIRECTION];
for (int index = 0; index < posToRender.getNumberOfPos(); index++)
{
detailLevel = posToRender.getNthDetailLevel(index);
@@ -266,12 +284,13 @@ public class LodBufferBuilder
// skip any chunks that Minecraft is going to render
try
{
if (lodDim.doesDataExist(detailLevel, posX, posZ))
//dataPoint = lodDim.getData(detailLevel, posX, posZ)[0];
for(long dataPoint : lodDim.getData(detailLevel, posX, posZ))
{
dataPoint = lodDim.getData(detailLevel, posX, posZ);
if (DataPoint.getHeight(dataPoint) == LodBuilder.DEFAULT_HEIGHT && DataPoint.getDepth(dataPoint) == LodBuilder.DEFAULT_DEPTH)
continue;
adjData = new long[NUMBER_OF_DIRECTION];
if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint))
{
/*
for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++)
{
xAdj = posX + ADJ_DIRECTION[direction][0];
@@ -284,22 +303,27 @@ public class LodBufferBuilder
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj);
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj)[0];
} else
{
adjData[direction] = 0;
}
}
else
} else
{
if (posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj);
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj)[0];
} else
{
adjData[direction] = 0;
}
}
}
}*/
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode);
}
}
catch (ArrayIndexOutOfBoundsException e)
}
} catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
return false;
@@ -23,27 +23,21 @@ import java.util.concurrent.Executors;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.objects.LevelPosUtil;
import com.seibel.lod.util.*;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.block.AbstractPlantBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.BushBlock;
import net.minecraft.block.GrassBlock;
import net.minecraft.block.IGrowable;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.*;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.DimensionType;
import net.minecraft.world.IWorld;
import net.minecraft.world.LightType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.IChunk;
@@ -169,9 +163,9 @@ public class LodBuilder
int endX;
int endZ;
int color;
byte light;
short height;
short depth;
long data;
try
{
LodDetail detail;
@@ -191,28 +185,31 @@ public class LodBuilder
endX = detail.endX[i];
endZ = detail.endZ[i];
color = generateLodColorForArea(chunk, config, startX, startZ, endX, endZ);
if (!config.useHeightmap)
{
height = determineHeightPointForArea(chunk.getSections(), startX, startZ, endX, endZ);
depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ);
} else
{
height = determineHeightPoint(chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP), startX,
startZ, endX, endZ);
depth = 0;
}
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
long[] data;
long[][] dataToMerge;
//data = ThreadMapUtil.getSingleAddDataArray();
//dataToMerge = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
/*long[][] dataToMerge2 = new long[dataToMerge.length][];
for (int index = 0; index < dataToMerge.length; index++)
{
dataToMerge2[index] = new long[]{dataToMerge[index]};
}*/
//data[0] = DataPointUtil.mergeSingleData(dataToMerge);
dataToMerge = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data = DataPointUtil.mergeVerticalData(dataToMerge);
if (data.length == 0 || data == null)
data = new long[]{DataPointUtil.EMPTY_DATA};
boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER;
data = DataPoint.createDataPoint(height, depth, ColorUtil.getRed(color), ColorUtil.getGreen(color), ColorUtil.getBlue(color));
lodDim.addData(detailLevel,
posX,
posZ,
data,
false,
isServer);
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
} catch (Exception e)
@@ -222,7 +219,199 @@ public class LodBuilder
}
private long[][] createVerticalDataToMerge(LodDetail detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ)
{
long[][] dataToMerge = ThreadMapUtil.getBuilderVerticalArray()[detail.detailLevel];
ChunkPos chunkPos = chunk.getPos();
int size = 1 << detail.detailLevel;
int height = 0;
int depth = 0;
int color = 0;
int light = 0;
int generation = config.distanceGenerationMode.complexity;
int xRel;
int zRel;
int xAbs;
int yAbs;
int zAbs;
BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0);
int index = 0;
if(dataToMerge == null){
dataToMerge = new long[size * size][DataPointUtil.WORLD_HEIGHT];
}
//dataToMerge = new long[size * size][1024];
for (index = 0; index < size * size; index++)
{
for(int i = 0; i < dataToMerge[index].length; i++)
{
dataToMerge[index][i] = 0;
}
xRel = Math.floorMod(index, size) + startX;
zRel = Math.floorDiv(index, size) + startZ;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
//Calculate the height of the lod
yAbs = 255;
int count = 0;
while (yAbs > 0)
{
height = determineHeightPointFrom(chunk, config, xRel, zRel, yAbs, blockPos);
//If the lod is at default, then we set this as void data
if (height == DEFAULT_HEIGHT)
{
dataToMerge[index][0] = DataPointUtil.createVoidDataPoint(generation);
break;
}
yAbs = height - 1;
// We search light on above air block
color = generateLodColor(chunk, config, xRel, yAbs, zRel);
depth = determineBottomPointFrom(chunk, config, xRel, zRel, yAbs, blockPos);
blockPos.set(xAbs, yAbs + 1, zAbs);
light = getLightValue(chunk, blockPos);
//System.out.println(dataToMerge.length + " " + index +" " + count + " " + yAbs);
//System.out.println(dataToMerge.length + " " + dataToMerge[index].length);
dataToMerge[index][count] = DataPointUtil.createDataPoint(height, depth, color, (light >> 4) & 0b1111, light & 0b1111, generation);
yAbs = depth - 1;
count++;
}
}
return dataToMerge;
}
/**
* Find the lowest valid point from the bottom.
*/
private short determineBottomPointFrom(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, int yAbs, BlockPos.Mutable blockPos)
{
short depth = DEFAULT_DEPTH;
if (config.useHeightmap)
{
depth = 0;
} else
{
boolean voidData = true;
ChunkSection[] chunkSections = chunk.getSections();
for (int sectionIndex = chunkSections.length - 1; sectionIndex >= 0; sectionIndex--)
{
for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--)
{
if (sectionIndex * CHUNK_DATA_WIDTH + yRel > yAbs)
continue;
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
if (!isLayerValidLodPoint(chunk, blockPos))
{
depth = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1);
voidData = false;
break;
}
}
if (!voidData)
{
break;
}
}
}
return depth;
}
/**
* Find the highest valid point from the Top
*/
private short determineHeightPointFrom(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, int yAbs, BlockPos.Mutable blockPos)
{
short height = DEFAULT_HEIGHT;
if (config.useHeightmap)
{
height = (short) chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
} else
{
boolean voidData = true;
ChunkSection[] chunkSections = chunk.getSections();
for (int sectionIndex = chunkSections.length - 1; sectionIndex >= 0; sectionIndex--)
{
for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--)
{
if (sectionIndex * CHUNK_DATA_WIDTH + yRel > yAbs)
continue;
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
if (isLayerValidLodPoint(chunk, blockPos))
{
height = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1);
voidData = false;
break;
}
}
if (!voidData)
{
break;
}
}
}
return height;
}
private long[] createSingleDataToMerge(LodDetail detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ)
{
long[] dataToMerge = ThreadMapUtil.getBuilderArray()[detail.detailLevel];
ChunkPos chunkPos = chunk.getPos();
int size = 1 << detail.detailLevel;
int height = 0;
int depth = 0;
int color = 0;
int light = 0;
int generation = config.distanceGenerationMode.complexity;
int xRel;
int zRel;
int xAbs;
int yAbs;
int zAbs;
BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0);
int index = 0;
if (dataToMerge == null)
{
dataToMerge = new long[size * size];
}
for (index = 0; index < size * size; index++)
{
xRel = Math.floorMod(index, size) + startX;
zRel = Math.floorDiv(index, size) + startZ;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
//Calculate the height of the lod
height = determineHeightPoint(chunk, config, xRel, zRel, blockPos);
//If the lod is at default, then we set this as void data
if (height == DEFAULT_HEIGHT)
{
dataToMerge[index] = DataPointUtil.createVoidDataPoint(generation);
continue;
}
yAbs = height - 1;
// We search light on above air block
color = generateLodColor(chunk, config, xRel, yAbs, zRel);
depth = determineBottomPoint(chunk, config, xRel, zRel, blockPos);
blockPos.set(xAbs, yAbs + 1, zAbs);
light = getLightValue(chunk, blockPos);
dataToMerge[index] = DataPointUtil.createDataPoint(height, depth, color, (light >> 4) & 0b1111, light & 0b1111, generation);
}
return dataToMerge;
}
// =====================//
// constructor helpers //
// =====================//
@@ -230,208 +419,118 @@ public class LodBuilder
/**
* Find the lowest valid point from the bottom.
*/
private short determineBottomPointForArea(ChunkSection[] chunkSections, int startX, int startZ, int endX, int endZ)
private short determineBottomPoint(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, BlockPos.Mutable blockPos)
{
int numberOfBlocksRequired = ((endX - startX) * (endZ - startZ) / 2);
// search from the bottom up
for (int section = 0; section < CHUNK_DATA_WIDTH; section++)
ChunkSection[] chunkSections = chunk.getSections();
short depth = DEFAULT_DEPTH;
if (config.useHeightmap)
{
for (int y = 0; y < CHUNK_SECTION_HEIGHT; y++)
depth = 0;
} else
{
boolean found = false;
for (int sectionIndex = 0; sectionIndex < chunkSections.length; sectionIndex++)
{
int numberOfBlocksFound = 0;
for (int x = startX; x < endX; x++)
for (int yRel = 0; yRel < CHUNK_DATA_WIDTH; yRel++)
{
for (int z = startZ; z < endZ; z++)
if (isLayerValidLodPoint(chunk, blockPos))
{
if (isLayerValidLodPoint(chunkSections, section, y, x, z))
{
numberOfBlocksFound++;
if (numberOfBlocksFound >= numberOfBlocksRequired)
{
// we found
// enough blocks in this
// layer to count as an
// LOD point
return (short) (y + (section * CHUNK_SECTION_HEIGHT));
}
}
depth = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel);
found = true;
break;
}
}
if (found)
{
break;
}
}
}
// we never found a valid LOD point
return DEFAULT_DEPTH;
return depth;
}
/**
* Find the lowest valid point from the bottom.
*/
@SuppressWarnings("unused")
private short determineBottomPoint(Heightmap heightmap)
{
// the heightmap only shows how high the blocks go, it
// doesn't have any info about how low they go
return 0;
}
/**
* Find the highest valid point from the Top
*/
private short determineHeightPointForArea(ChunkSection[] chunkSections, int startX, int startZ, int endX, int endZ)
private short determineHeightPoint(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, BlockPos.Mutable blockPos)
{
int numberOfBlocksRequired = ((endX - startX) * (endZ - startZ) / 2);
// search from the top down
for (int section = chunkSections.length - 1; section >= 0; section--)
short height = DEFAULT_HEIGHT;
if (config.useHeightmap)
{
for (int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--)
height = (short) chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
} else
{
boolean voidData = true;
ChunkSection[] chunkSections = chunk.getSections();
for (int sectionIndex = chunkSections.length - 1; sectionIndex >= 0; sectionIndex--)
{
int numberOfBlocksFound = 0;
for (int x = startX; x < endX; x++)
for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--)
{
for (int z = startZ; z < endZ; z++)
if (isLayerValidLodPoint(chunk, blockPos))
{
if (isLayerValidLodPoint(chunkSections, section, y, x, z))
{
numberOfBlocksFound++;
if (numberOfBlocksFound >= numberOfBlocksRequired)
{
// we found
// enough blocks in this
// layer to count as an
// LOD point
return (short) (y + 1 + (section * CHUNK_SECTION_HEIGHT));
}
}
height = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1);
voidData = false;
break;
}
}
if (!voidData)
{
break;
}
}
}
// we never found a valid LOD point
return DEFAULT_HEIGHT;
}
/**
* Find the highest point from the Top
*/
private short determineHeightPoint(Heightmap heightmap, int startX, int startZ, int endX, int endZ)
{
short highest = 0;
for (int x = startX; x < endX; x++)
{
for (int z = startZ; z < endZ; z++)
{
short newHeight = (short) heightmap.getFirstAvailable(x, z);
if (newHeight > highest)
highest = newHeight;
}
}
return highest;
return height;
}
/**
* Generate the color for the given chunk using biome water color, foliage
* color, and grass color.
*
* @param config_useSolidBlocksInColorGen <br>
* If true we look down from the top of
* the <br>
* chunk until we find a non-invisible
* block, and then use <br>
* its color. If false we generate the
* color immediately for <br>
* each x and z.
* @param config_useBiomeColors <br>
* If true use biome foliage, water, and
* grass colors, <br>
* otherwise only use the block's
* material color
*/
private int generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX,
int endZ)
private int generateLodColor(IChunk chunk, LodBuilderConfig config, int xRel, int yAbs, int zRel)
{
ChunkSection[] chunkSections = chunk.getSections();
int numbOfBlocks = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int x = startX; x < endX; x++)
int colorInt = 0;
if (config.useBiomeColors)
{
for (int z = startZ; z < endZ; z++)
// I have no idea why I need to bit shift to the right, but
// if I don't the biomes don't show up correctly.
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, yAbs >> 2, zRel >> 2);
colorInt = getColorForBiome(xRel, zRel, biome);
} else
{
int sectionIndex = Math.floorDiv(yAbs, CHUNK_SECTION_HEIGHT);
int yRel = Math.floorMod(yAbs, CHUNK_SECTION_HEIGHT);
if (chunkSections[sectionIndex] != null)
{
boolean foundBlock = false;
BlockState blockState = chunkSections[sectionIndex].getBlockState(xRel, yRel, zRel);
// go top down
for (int i = chunkSections.length - 1; !foundBlock && i >= 0; i--)
{
if (!foundBlock && (chunkSections[i] != null || !config.useSolidBlocksInColorGen))
{
for (int y = CHUNK_SECTION_HEIGHT - 1; !foundBlock && y >= 0; y--)
{
int colorInt = 0;
BlockState blockState = null;
// the bit shift is equivalent to dividing by 4
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, yAbs >> 2, zRel >> 2);
if (chunkSections[i] != null)
{
blockState = chunkSections[i].getBlockState(x, y, z);
colorInt = blockState.materialColor.col;
}
if (colorInt == 0 && config.useSolidBlocksInColorGen)
{
// skip air or invisible blocks
continue;
}
if (config.useBiomeColors)
{
// I have no idea why I need to bit shift to the right, but
// if I don't the biomes don't show up correctly.
Biome biome = chunk.getBiomes().getNoiseBiome(x >> 2, y + 1 * chunkSections.length >> 2,
z >> 2);
colorInt = getColorForBiome(x, z, biome);
} else
{
// the bit shift is equivalent to dividing by 4
Biome biome = chunk.getBiomes().getNoiseBiome(x >> 2, y + i * chunkSections.length >> 2,
z >> 2);
colorInt = getColorForBlock(x, z, blockState, biome);
}
red += ColorUtil.getRed(colorInt);
green += ColorUtil.getGreen(colorInt);
blue += ColorUtil.getBlue(colorInt);
numbOfBlocks++;
// we found a valid block, skip to the
// next x and z
foundBlock = true;
}
}
}
colorInt = getColorForBlock(xRel, zRel, blockState, biome);
}
if (colorInt == 0 && yAbs > 0)
{
//invisible case
colorInt = generateLodColor(chunk, config, xRel, yAbs - 1, zRel);
}
}
return colorInt;
}
if (numbOfBlocks == 0)
numbOfBlocks = 1;
private int getLightValue(IChunk chunk, BlockPos.Mutable blockPos)
{
int light;
red /= numbOfBlocks;
green /= numbOfBlocks;
blue /= numbOfBlocks;
return ColorUtil.rgbToInt(red,green,blue);
//*TODO choose the best one between those options*/
//lightBlock = MinecraftWrapper.INSTANCE.getPlayer().level.getLightEngine().getLayerListener(LightType.BLOCK).getLightValue(blockPos);
//lightBlock = (byte) MinecraftWrapper.INSTANCE.getPlayer().level.getLightEngine().blockEngine.getLightValue(blockPos);
light = MinecraftWrapper.INSTANCE.getPlayer().level.getBrightness(LightType.BLOCK, blockPos);
light += MinecraftWrapper.INSTANCE.getPlayer().level.getBrightness(LightType.SKY, blockPos) << 4;
//BlockState blockState = chunk.getBlockState(blockPos);
//lightBlock = (byte) blockState.getLightBlock(chunk, blockPos);
return light;
}
/**
@@ -442,9 +541,9 @@ public class LodBuilder
int colorInt = 0;
// block special cases
if (blockState == Blocks.AIR.defaultBlockState()
|| blockState == Blocks.CAVE_AIR.defaultBlockState()
|| blockState == Blocks.BARRIER.defaultBlockState())
if (blockState == Blocks.AIR.defaultBlockState()
|| blockState == Blocks.CAVE_AIR.defaultBlockState()
|| blockState == Blocks.BARRIER.defaultBlockState())
{
Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z));
tmp = tmp.darker();
@@ -452,11 +551,36 @@ public class LodBuilder
} else if (blockState == Blocks.STONE.defaultBlockState())
{
colorInt = LodUtil.STONE_COLOR_INT;
} else if (blockState == Blocks.NETHERRACK.defaultBlockState())
{
colorInt = LodUtil.NETHERRACK_COLOR_INT;
} else if (blockState == Blocks.WARPED_NYLIUM.defaultBlockState())
{
colorInt = LodUtil.WARPED_NYLIUM_COLOR_INT;
} else if (blockState == Blocks.CRIMSON_NYLIUM.defaultBlockState())
{
colorInt = LodUtil.CRIMSON_NYLIUM_COLOR_INT;
} else if (blockState == Blocks.BEDROCK.defaultBlockState())
{
colorInt = getColorForBiome(x, z, biome);
} else if (blockState == Blocks.MYCELIUM.defaultBlockState())
{
colorInt = LodUtil.MYCELIUM_COLOR_INT;
} else if (blockState == Blocks.SOUL_TORCH.defaultBlockState()
|| blockState == Blocks.SOUL_WALL_TORCH.defaultBlockState())
{
colorInt = Blocks.WARPED_PLANKS.defaultMaterialColor().col;
} else if (blockState == Blocks.TORCH.defaultBlockState()
|| blockState == Blocks.WALL_TORCH.defaultBlockState())
{
colorInt = Blocks.OAK_PLANKS.defaultMaterialColor().col;
} else if (blockState == Blocks.REDSTONE_TORCH.defaultBlockState()
|| blockState == Blocks.REDSTONE_WALL_TORCH.defaultBlockState())
{
colorInt = Blocks.CRIMSON_PLANKS.defaultMaterialColor().col;
}
// plant life
else if (blockState.getBlock() instanceof LeavesBlock || blockState.getBlock() == Blocks.VINE)
{
@@ -481,7 +605,7 @@ public class LodBuilder
// everything else
else
{
colorInt = blockState.materialColor.col;
colorInt = blockState.getBlock().defaultMaterialColor().col;
}
return colorInt;
@@ -498,7 +622,7 @@ public class LodBuilder
{
case NETHER:
colorInt = Blocks.BEDROCK.defaultBlockState().materialColor.col;
colorInt = LodUtil.NETHERRACK_COLOR_INT;
break;
case THEEND:
@@ -552,19 +676,34 @@ public class LodBuilder
/**
* Is the layer between the given X, Z, and dataIndex values a valid LOD point?
*/
private boolean isLayerValidLodPoint(ChunkSection[] chunkSections, int sectionIndex, int y, int x, int z)
private boolean isLayerValidLodPoint(IChunk chunk, BlockPos.Mutable blockPos)
{
if (chunkSections[sectionIndex] == null)
BlockState blockState = chunk.getBlockState(blockPos);
if (blockState != null)
{
// this section doesn't have any blocks,
// it is not a valid section
return false;
} else
{
if (chunkSections[sectionIndex].getBlockState(x, y, z) != null
&& chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.AIR
&& chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.CAVE_AIR
&& chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.BARRIER)
if (!blockState.getFluidState().isEmpty())
{
return true;
}
VoxelShape voxelShape = blockState.getShape(chunk, blockPos);
if (!voxelShape.isEmpty())
{
AxisAlignedBB bbox = voxelShape.bounds();
int xWidth = (int) (bbox.maxX - bbox.minX);
int yWidth = (int) (bbox.maxY - bbox.minY);
int zWidth = (int) (bbox.maxZ - bbox.minZ);
if (xWidth < 0.7 && zWidth < 0.7 && yWidth < 1)
{
return false;
}
} else
{
return false;
}
if (blockState.getBlock() != Blocks.AIR
&& blockState.getBlock() != Blocks.CAVE_AIR
&& blockState.getBlock() != Blocks.BARRIER)
{
return true;
}
@@ -20,6 +20,7 @@ package com.seibel.lod.builders.lodTemplates;
import com.seibel.lod.enums.DebugMode;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
/**
@@ -31,6 +32,8 @@ import net.minecraft.util.math.BlockPos;
*/
public abstract class AbstractLodTemplate
{
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging);
@@ -41,6 +44,7 @@ public abstract class AbstractLodTemplate
double x, double y, double z,
int red, int green, int blue, int alpha)
{
buffer.vertex(x, y, z).color(red, green, blue, alpha).endVertex();
}
@@ -20,10 +20,11 @@ package com.seibel.lod.builders.lodTemplates;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.enums.ShadingMode;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.Direction;
@@ -53,21 +54,29 @@ public class CubicLodTemplate extends AbstractLodTemplate
// add each LOD for the detail level
generateBoundingBox(
box,
DataPoint.getHeight(data),
DataPoint.getDepth(data),
DataPointUtil.getHeight(data),
DataPointUtil.getDepth(data),
width,
posX * width,
0,
posZ * width,
bufferCenterBlockPos);
int color;
boolean hasSkyLight = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasSkyLight();
boolean hasRoof = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasSkyLight();
int time = (int) (MinecraftWrapper.INSTANCE.getPlayer().level.getDayTime() - 13000);
boolean isDay = time < 0;
//USE THIS IN THE boolean hasCeiling = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasCeiling();
color = DataPointUtil.getLightColor(data, (hasRoof & hasSkyLight), isDay);
int color = DataPoint.getColor(data);
if (debugging != DebugMode.OFF)
{
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
}
if (box != null)
{
addBoundingBoxToBuffer(buffer, box, color, bufferCenterBlockPos, adjData);
}
@@ -208,10 +217,10 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
}else
} else
{
maxY = box.getMaxY();
tempMaxY = DataPoint.getHeight(data);
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
@@ -220,7 +229,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
}
tempMinY = DataPoint.getDepth(data);
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
@@ -253,11 +262,10 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
else
} else
{
maxY = box.getMaxY();
tempMaxY = DataPoint.getHeight(data);
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
@@ -266,7 +274,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
tempMinY = DataPoint.getDepth(data);
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
@@ -299,11 +307,10 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
}
else
} else
{
maxY = box.getMaxY();
tempMaxY = DataPoint.getHeight(data);
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
@@ -312,7 +319,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
}
tempMinY = DataPoint.getDepth(data);
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
@@ -345,11 +352,10 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
else
} else
{
maxY = box.getMaxY();
tempMaxY = DataPoint.getHeight(data);
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
@@ -358,7 +364,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
tempMinY = DataPoint.getDepth(data);
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
@@ -24,8 +24,10 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.function.Supplier;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.builders.LodBuilderConfig;
import com.seibel.lod.config.LodConfig;
@@ -72,7 +74,8 @@ import net.minecraftforge.common.WorldWorkerManager.IWorker;
*/
public class LodNodeGenWorker implements IWorker
{
public static ExecutorService genThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfWorldGenerationThreads.get(), new LodThreadFactory(LodNodeGenWorker.class.getSimpleName()));
public static ExecutorService genThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfWorldGenerationThreads.get(), new ThreadFactoryBuilder().setNameFormat("Gen-Worker-Thread-%d").build());
//public static ExecutorService genThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfWorldGenerationThreads.get(), new LodThreadFactory(LodNodeGenWorker.class.getSimpleName()));
private boolean threadStarted = false;
private LodChunkGenThread thread;
@@ -126,7 +129,7 @@ public class LodNodeGenWorker implements IWorker
// Every other method can
// be done asynchronously
Thread newThread = new Thread(thread);
newThread.setPriority(3);
newThread.setPriority(5);
genThreads.execute(newThread);
}
@@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.objects.LevelPosUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.PosToGenerateContainer;
import com.seibel.lod.render.LodRenderer;
@@ -28,10 +28,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.objects.LevelContainer;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.objects.*;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
@@ -46,11 +43,6 @@ import com.seibel.lod.util.LodUtil;
*/
public class LodDimensionFileHandler
{
/**
* This is what separates each piece of data
*/
public static final char DATA_DELIMITER = ',';
private LodDimension loadedDimension = null;
public long regionLastWriteTime[][];
@@ -84,7 +76,7 @@ public class LodDimensionFileHandler
* file handler, older versions (smaller numbers) will be deleted and overwritten,
* newer versions (larger numbers) will be ignored and won't be read.
*/
public static final int LOD_SAVE_FILE_VERSION = 5;
public static final int LOD_SAVE_FILE_VERSION = 6;
/**
* This is the string written before the file version
@@ -200,7 +192,8 @@ public class LodDimensionFileHandler
data = bufferedReader.readLine();
bufferedReader.close();
region.addLevel(new LevelContainer(data));
//region.addLevel(new SingleLevelContainer(data));
region.addLevel(new VerticalLevelContainer(data));
} catch (Exception e)
{
// the buffered reader encountered a
@@ -331,7 +324,7 @@ public class LodDimensionFileHandler
fw.write(LOD_FILE_VERSION_PREFIX + " " + LOD_SAVE_FILE_VERSION + "\n");
// add each LodChunk to the file
fw.write(region.getLevel(detailLevel).toString());
fw.write(region.getLevel(detailLevel).toDataString());
fw.close();
// overwrite the old file with the new one
@@ -1,97 +0,0 @@
package com.seibel.lod.objects;
public class DataPoint
{
public final static int HEIGHT_SHIFT = 54;
public final static int DEPTH_SHIFT = 44;
public final static int RED_SHIFT = 36;
public final static int GREEN_SHIFT = 28;
public final static int BLUE_SHIFT = 20;
public final static int GEN_TYPE_SHIFT = 17;
public final static int LIGHT_SHIFT = 13;
public final static int EXISTENCE_SHIFT = 0;
public final static long HEIGHT_MASK = Long.parseUnsignedLong("1111111111", 2);
public final static long DEPTH_MASK = Long.parseUnsignedLong("1111111111", 2);
public final static long RED_MASK = Long.parseUnsignedLong("11111111", 2);
public final static long GREEN_MASK = Long.parseUnsignedLong("11111111", 2);
public final static long BLUE_MASK = Long.parseUnsignedLong("11111111", 2);
public final static long GEN_TYPE_MASK = Long.parseUnsignedLong("111", 2);
public final static long LIGHT_MASK = Long.parseUnsignedLong("1111", 2);
public final static long EXISTENCE_MASK = 1;
public static long createDataPoint(int height, int depth, int color)
{
int red = (getRed(color) << 16) & 0x00FF0000;
int green = (getGreen(color) << 8) & 0x0000FF00;
int blue = getBlue(color)& 0x000000FF;
return createDataPoint(height, depth, red, green, blue);
}
public static long createDataPoint(int height, int depth, int red, int green, int blue)
{
long dataPoint = 0;
dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT;
dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT;
dataPoint += (red & RED_MASK) << RED_SHIFT;
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT;
dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT;
dataPoint += 1;
return dataPoint;
}
public static short getHeight(long dataPoint)
{
return (short) ((dataPoint >> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(long dataPoint)
{
return (short) ((dataPoint >> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getRed(long dataPoint)
{
return (short) ((dataPoint >> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
{
return (short) ((dataPoint >> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
{
return (short) ((dataPoint >> BLUE_SHIFT) & BLUE_MASK);
}
public static boolean doesItExist(long dataPoint)
{
return ((dataPoint & EXISTENCE_MASK) == 1);
}
public static int getColor(long dataPoint)
{
int R = (getRed(dataPoint) << 16) & 0x00FF0000;
int G = (getGreen(dataPoint) << 8) & 0x0000FF00;
int B = getBlue(dataPoint)& 0x000000FF;
return 0xFF000000 | R | G | B;
}
public static String toString(long dataPoint)
{
StringBuilder s = new StringBuilder();
s.append(getHeight(dataPoint));
s.append(" ");
s.append(getDepth(dataPoint));
s.append(" ");
s.append(getRed(dataPoint));
s.append(" ");
s.append(getBlue(dataPoint));
s.append(" ");
s.append(getGreen(dataPoint));
s.append('\n');
return s.toString();
}
}
@@ -1,67 +1,61 @@
package com.seibel.lod.objects;
import java.io.Serializable;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
public class LevelContainer implements Serializable
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public interface LevelContainer
{
public static final char VERTICAL_DATA_DELIMITER = '\t';
public static final char DATA_DELIMITER = ' ';
/**With this you can add data to the level container
*
* @param data actual data to add in a array of long format.
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
public boolean addData(long[] data, int posX, int posZ);
/** This is here so that Eclipse doesn't complain */
private static final long serialVersionUID = -4930855068717998385L;
/**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
*/
public long[] getData(int posX, int posZ);
public static final char DATA_DELIMITER = ',';
/**
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true only if the data exist
*/
public boolean doesItExist(int posX, int posZ);
public final byte detailLevel;
/**
* @return return the deatilLevel of this level container
*/
public byte getDetailLevel();
public final long[][] data;
/**This return a level container with detail level lower than the current level.
* The new level container may use information of this level.
* @return the new level container
*/
public LevelContainer expand();
public LevelContainer(byte detailLevel, long[][] data)
{
this.detailLevel = detailLevel;
this.data = data;
}
/**
*
* @param lowerLevelContainer lower level where we extract the data
* @param posX x position in the detail level to update
* @param posZ z position in the detail level to update
*/
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ);
public LevelContainer(String inputString)
{
int index = 0;
int lastIndex = 0;
index = inputString.indexOf(DATA_DELIMITER, 0);
this.detailLevel = (byte) Integer.parseInt(inputString.substring(0, index));
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
this.data = new long[size][size];
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
lastIndex = index;
index = inputString.indexOf(DATA_DELIMITER, lastIndex + 1);
data[x][z] = Long.parseLong(inputString.substring(lastIndex + 1, index), 16);
}
}
}
@Override
public String toString()
{
StringBuilder stringBuilder = new StringBuilder();
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
stringBuilder.append(detailLevel);
stringBuilder.append(DATA_DELIMITER);
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
//Converting the dataToHex
stringBuilder.append(Long.toHexString(data[x][z]));
stringBuilder.append(DATA_DELIMITER);
}
}
return stringBuilder.toString();
}
/**
* This will give the data to save in the file
* @return data as a String
*/
public String toDataString();
}
@@ -25,9 +25,7 @@ import java.util.concurrent.Executors;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.handlers.LodDimensionFileHandler;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.*;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.util.math.ChunkPos;
@@ -435,7 +433,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinates it will be overwritten.
*/
public synchronized Boolean addData(byte detailLevel, int posX, int posZ, long lodDataPoint, boolean dontSave, boolean serverQuality)
public Boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
@@ -445,7 +443,7 @@ public class LodDimension
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
boolean nodeAdded = region.addData(detailLevel, posX, posZ, lodDataPoint, serverQuality);
boolean nodeAdded = region.addData(detailLevel, posX, posZ, dataPoint, serverQuality);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
{
@@ -520,7 +518,7 @@ public class LodDimension
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public long getData(byte detailLevel, int posX, int posZ)
public long[] getData(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.");
@@ -529,7 +527,7 @@ public class LodDimension
if (region == null)
{
return 0;
return new long[]{DataPointUtil.EMPTY_DATA};
}
return region.getData(detailLevel, posX, posZ);
@@ -3,7 +3,9 @@ package com.seibel.lod.objects;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
/**
@@ -20,65 +22,61 @@ public class LodRegion
private byte minDetailLevel;
private static final byte POSSIBLE_LOD = 10;
//private int numberOfPoints;
private DistanceGenerationMode generationMode;
//For each of the following field the first slot is for the level of detail
//Important: byte have a [-128, 127] range. When converting from or to int a 128 should be added or removed
//If there is a bug with color then it's probably caused by this.
//in the future other fields like transparency and light level could be added
private long[][][] data;
private LevelContainer[] dataContainer;
private DistanceGenerationMode generationMode;
public final int regionPosX;
public final int regionPosZ;
public LodRegion(LevelContainer levelContainer, RegionPos regionPos, DistanceGenerationMode generationMode)
public LodRegion(RegionPos regionPos)
{
this.generationMode = generationMode;
this.minDetailLevel = LodUtil.REGION_DETAIL_LEVEL;
this.regionPosX = regionPos.x;
this.regionPosZ = regionPos.z;
this.minDetailLevel = levelContainer.detailLevel;
//Arrays of matrices
data = new long[POSSIBLE_LOD][][];
data[minDetailLevel] = levelContainer.data;
//Initialize all the different matrices
for (byte lod = (byte) (minDetailLevel + 1); lod <= LodUtil.REGION_DETAIL_LEVEL; lod++)
{
int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod);
data[lod] = new long[size][size];
}
updateArea(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ);
dataContainer = new LevelContainer[POSSIBLE_LOD];
}
public LodRegion(byte minDetailLevel, RegionPos regionPos, DistanceGenerationMode generationMode)
{
this.generationMode = generationMode;
this.minDetailLevel = minDetailLevel;
this.regionPosX = regionPos.x;
this.regionPosZ = regionPos.z;
data = new long[POSSIBLE_LOD][][];
this.generationMode = generationMode;
dataContainer = new LevelContainer[POSSIBLE_LOD];
//Initialize all the different matrices
for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++)
{
int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod);
data[lod] = new long[size][size];
//dataContainer[lod] = new SingleLevelContainer(lod);
dataContainer[lod] = new VerticalLevelContainer(lod);
/*if(twoDimension){
dataContainer[lod] = new SingleLevelContainer(lod);
}else{
dataContainer[lod] = new VerticalLevelContainer.java(lod);
}*/
}
}
public DistanceGenerationMode getGenerationMode()
{
return generationMode;
}
/**
* This method can be used to insert data into the LodRegion
*
* @param dataPoint
* @return
*/
public boolean addData(byte detailLevel, int posX, int posZ, long dataPoint, boolean serverQuality)
public boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean serverQuality)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
@@ -89,7 +87,7 @@ public class LodRegion
//if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++;
//add the node data
this.data[detailLevel][posX][posZ] = dataPoint;
this.dataContainer[detailLevel].addData(dataPoint, posX, posZ);
return true;
} else
{
@@ -102,11 +100,11 @@ public class LodRegion
*
* @return the data at the relative pos and level
*/
public long getData(byte detailLevel, int posX, int posZ)
public long[] getData(byte detailLevel, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return data[detailLevel][posX][posZ];
return dataContainer[detailLevel].getData(posX, posZ);
}
/**
@@ -135,11 +133,11 @@ public class LodRegion
int childSize = 1 << (LodUtil.REGION_DETAIL_LEVEL - childDetailLevel);
//we have reached the target detail level
if (DetailDistanceUtil.getDistanceGenerationInverse(maxDistance) > detailLevel)
byte targetDetailLevel = DetailDistanceUtil.getLodGenDetail(DetailDistanceUtil.getDistanceGenerationInverse(maxDistance)).detailLevel;
if (targetDetailLevel > detailLevel)
{
return;
} else if (DetailDistanceUtil.getDistanceGenerationInverse(maxDistance) == detailLevel)
} else if (targetDetailLevel == detailLevel)
{
if (!doesDataExist(detailLevel, posX, posZ))
{
@@ -286,63 +284,7 @@ public class LodRegion
*/
private void update(byte detailLevel, int posX, int posZ)
{
int numberOfChildren = 0;
int numberOfVoidChildren = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempHeight = 0;
int tempDepth = 0;
int childPosX;
int childPosZ;
byte childDetailLevel;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
{
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
childDetailLevel = (byte) (detailLevel - 1);
if (doesDataExist(childDetailLevel, childPosX, childPosZ))
{
if (!(DataPoint.getHeight(data[childDetailLevel][childPosX][childPosZ]) == LodBuilder.DEFAULT_HEIGHT
&& DataPoint.getDepth(data[childDetailLevel][childPosX][childPosZ]) == LodBuilder.DEFAULT_DEPTH))
{
numberOfChildren++;
tempRed += DataPoint.getRed(data[childDetailLevel][childPosX][childPosZ]);
tempGreen += DataPoint.getGreen(data[childDetailLevel][childPosX][childPosZ]);
tempBlue += DataPoint.getBlue(data[childDetailLevel][childPosX][childPosZ]);
tempHeight += DataPoint.getHeight(data[childDetailLevel][childPosX][childPosZ]);
tempDepth += DataPoint.getDepth(data[childDetailLevel][childPosX][childPosZ]);
} else
{
// void children have the default height (most likely -1)
// and represent a LOD with no blocks in it
numberOfVoidChildren++;
}
}
}
}
if (numberOfChildren > 0)
{
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempHeight = tempHeight / numberOfChildren;
tempDepth = tempDepth / numberOfChildren;
} else if (numberOfVoidChildren > 0)
{
tempRed = (byte) 0;
tempGreen = (byte) 0;
tempBlue = (byte) 0;
tempHeight = LodBuilder.DEFAULT_HEIGHT;
tempDepth = LodBuilder.DEFAULT_DEPTH;
}
data[detailLevel][posX][posZ] = DataPoint.createDataPoint(tempHeight, tempDepth, tempRed, tempGreen, tempBlue);
dataContainer[detailLevel].updateData(dataContainer[detailLevel - 1], posX, posZ);
}
@@ -354,15 +296,24 @@ public class LodRegion
if(detailLevel < minDetailLevel) return false;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return DataPoint.doesItExist(data[detailLevel][posX][posZ]);
if(dataContainer == null || dataContainer[detailLevel] == null)
return false;
return dataContainer[detailLevel].doesItExist(posX, posZ);
}
/**
* @return
*/
public DistanceGenerationMode getGenerationMode()
public byte getGenerationMode(byte detailLevel, int posX, int posZ)
{
return generationMode;
if(dataContainer[detailLevel].doesItExist(posX,posZ))
{
//We take the bottom information always
return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getData(posX,posZ)[0]);
}else
{
return DistanceGenerationMode.NONE.complexity;
}
}
public byte getMinDetailLevel()
@@ -382,7 +333,7 @@ public class LodRegion
{
throw new IllegalArgumentException("getLevel asked for a level that does not exist: minimum " + minDetailLevel + " level requested " + detailLevel);
}
return new LevelContainer(detailLevel, data[detailLevel]);
return dataContainer[detailLevel];
}
/**
@@ -390,12 +341,12 @@ public class LodRegion
*/
public void addLevel(LevelContainer levelContainer)
{
if (levelContainer.detailLevel < minDetailLevel - 1)
if (levelContainer.getDetailLevel() < minDetailLevel - 1)
{
throw new IllegalArgumentException("addLevel requires a level that is at least the minimum level of the region -1 ");
}
if (levelContainer.detailLevel == minDetailLevel - 1) minDetailLevel = levelContainer.detailLevel;
data[levelContainer.detailLevel] = levelContainer.data;
if (levelContainer.getDetailLevel() == minDetailLevel - 1) minDetailLevel = levelContainer.getDetailLevel();
dataContainer[levelContainer.getDetailLevel()] = levelContainer;
}
@@ -408,7 +359,7 @@ public class LodRegion
{
for (byte tempLod = 0; tempLod < detailLevel; tempLod++)
{
data[tempLod] = new long[0][0];
dataContainer[tempLod] = null;
}
minDetailLevel = detailLevel;
}
@@ -421,10 +372,13 @@ public class LodRegion
{
if (detailLevel < minDetailLevel)
{
for (byte tempLod = detailLevel; tempLod < minDetailLevel; tempLod++)
for (byte tempLod = (byte) (minDetailLevel - 1); tempLod >= detailLevel ; tempLod--)
{
int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - tempLod);
data[tempLod] = new long[size][size];
if(dataContainer[tempLod + 1] == null)
{
dataContainer[tempLod + 1] = new SingleLevelContainer((byte) (tempLod + 1));
}
dataContainer[tempLod] = dataContainer[tempLod+1].expand();
}
minDetailLevel = detailLevel;
}
@@ -1,5 +1,7 @@
package com.seibel.lod.objects;
import com.seibel.lod.util.LevelPosUtil;
public class PosToGenerateContainer
{
private int playerPosX;
@@ -1,5 +1,6 @@
package com.seibel.lod.objects;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
public class PosToRenderContainer
@@ -0,0 +1,153 @@
package com.seibel.lod.objects;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.util.*;
public class SingleLevelContainer implements LevelContainer
{
public final byte detailLevel;
public final int size;
public final long[][] data;
public SingleLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
data = new long[size][size];
}
public boolean addData(long[] newData, int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
data[posX][posZ] = newData[0];
return true;
}
private boolean addSingleData(long newData, int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
data[posX][posZ] = newData;
return true;
}
public long[] getData(int posX, int posZ){
long[] dataArray = ThreadMapUtil.getSingleGetDataArray();
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//Improve this using a thread map to long[]
dataArray[0] = data[posX][posZ];
return dataArray;
}
private long getSingleData(int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//Improve this using a thread map to long[]
return data[posX][posZ];
}
public byte getDetailLevel(){
return detailLevel;
}
public LevelContainer expand(){
return new SingleLevelContainer((byte) (getDetailLevel() - 1));
}
public SingleLevelContainer(String inputString)
{
int tempIndex;
int shift = 0;
int index = 0;
int digit;
char currentChar;
long newData;
currentChar = inputString.charAt(index);
digit = Character.digit(currentChar,16);
detailLevel = (byte) digit;
size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
this.data = new long[size][size];
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
newData = 0;
for(tempIndex = 0; tempIndex < 16; tempIndex++)
{
if(index+tempIndex >= inputString.length())
break;
currentChar = inputString.charAt(index+tempIndex);
if(currentChar == DATA_DELIMITER){
break;
}
shift = (15-tempIndex)*4;
digit = Character.digit(currentChar,16);
newData += ((((long) digit & 0xf)) << shift);
}
newData = newData >>> (shift);
data[x][z] = newData;
index = index + tempIndex;
}
}
}
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{
//We reset the array
long[] dataToMerge = ThreadMapUtil.getSingleUpdateArray();
int childPosX;
int childPosZ;
long data = 0;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
{
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
dataToMerge[2*x + z] = ((SingleLevelContainer) lowerLevelContainer).getSingleData(childPosX, childPosZ);
}
}
data = DataPointUtil.mergeSingleData(dataToMerge);
addSingleData(data,posX,posZ);
}
public boolean doesItExist(int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//Improve this using a thread map to long[]
return DataPointUtil.doesItExist(getSingleData(posX, posZ));
}
public String toDataString()
{
StringBuilder stringBuilder = new StringBuilder();
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
stringBuilder.append(detailLevel);
stringBuilder.append(DATA_DELIMITER);
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
//Converting the dataToHex
stringBuilder.append(Long.toHexString(data[x][z]));
stringBuilder.append(DATA_DELIMITER);
}
}
return stringBuilder.toString();
}
@Override
public String toString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(detailLevel);
return stringBuilder.toString();
}
}
@@ -0,0 +1,129 @@
package com.seibel.lod.objects;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.ThreadMapUtil;
import java.security.InvalidParameterException;
public class VerticalLevelContainer implements LevelContainer
{
public final byte detailLevel;
public final long[][][] dataContainer;
public VerticalLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
dataContainer = new long[size][size][1];
}
@Override
public byte getDetailLevel()
{
return detailLevel;
}
public boolean addData(long[] newData, int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[posX][posZ] = newData;
return true;
}
public long[] getData(int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[posX][posZ];
}
public boolean doesItExist(int posX, int posZ){
long[] data = getData(posX,posZ);
if(data == null)
return false;
return DataPointUtil.doesItExist(data[0]);
}
public VerticalLevelContainer(String inputString)
{
throw new InvalidParameterException("loading not yet implemented");
/*
int index = 0;
int lastIndex = 0;
index = inputString.indexOf(DATA_DELIMITER, 0);
this.detailLevel = (byte) Integer.parseInt(inputString.substring(0, index));
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
this.dataContainer = new long[size][size][1];
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
lastIndex = index;
index = inputString.indexOf(DATA_DELIMITER, lastIndex + 1);
dataContainer[x][z][0] = Long.parseLong(inputString.substring(lastIndex + 1, index), 16);
}
}*/
}
public LevelContainer expand(){
return new VerticalLevelContainer((byte) (getDetailLevel() - 1));
}
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{
//We reset the array
long[][] dataToMerge = ThreadMapUtil.getVerticalUpdateArray();
int childPosX;
int childPosZ;
long[] data;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
{
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
dataToMerge[2*z + x] = lowerLevelContainer.getData(childPosX, childPosZ);
}
}
data = DataPointUtil.mergeVerticalData(dataToMerge);
addData(data,posX,posZ);
}
public String toDataString()
{
return toString();
}
@Override
public String toString()
{
/*
StringBuilder stringBuilder = new StringBuilder();
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
stringBuilder.append(detailLevel);
stringBuilder.append(DATA_DELIMITER);
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
//Converting the dataToHex
stringBuilder.append(Long.toHexString(dataContainer[x][z][0]));
stringBuilder.append(DATA_DELIMITER);
}
}
return stringBuilder.toString();
*/
return " ";
}
}
@@ -101,7 +101,7 @@ public class ClientProxy
public void renderLods(float partialTicks)
{
// only run the first time setup once
if (firstTimeSetupComplete)
if (!firstTimeSetupComplete)
{
firstFrameSetup();
}
@@ -39,7 +39,7 @@ import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogDrawOverride;
import com.seibel.lod.enums.FogQuality;
import com.seibel.lod.handlers.ReflectionHandler;
import com.seibel.lod.objects.LevelPosUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.NearFarFogSettings;
import com.seibel.lod.objects.RegionPos;
@@ -551,7 +551,7 @@ public class LodRenderer
// it is possible to see the near clip plane, but
// you have to be flying quickly in spectator mode through ungenerated
// terrain, so I don't think it is much of an issue.
mc.getRenderDistance(),
mc.getRenderDistance()/2,
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH * 2);
// add the screen space distortions
@@ -0,0 +1,390 @@
package com.seibel.lod.util;
import com.seibel.lod.enums.DistanceGenerationMode;
import net.minecraft.client.renderer.LightTexture;
public class DataPointUtil
{
/*
|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 |
*/
//To be used in the future for negative value
//public final static int MIN_DEPTH = -64;
//public final static int MIN_HEIGHT = -64;
public final static int EMPTY_DATA = 0;
public final static int WORLD_HEIGHT = 256;
public final static int ALPHA_DOWNSIZE_SHIFT = 4;
public final static int BLUE_COLOR_SHIFT = 0;
public final static int GREEN_COLOR_SHIFT = 8;
public final static int RED_COLOR_SHIFT = 16;
public final static int ALPHA_COLOR_SHIFT = 24;
public final static int BLUE_SHIFT = 36;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16 ;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24;
public final static int COLOR_SHIFT = 36;
public final static int HEIGHT_SHIFT = 26;
public final static int DEPTH_SHIFT = 16;
public final static int BLOCK_LIGHT_SHIFT = 12;
public final static int SKY_LIGHT_SHIFT = 8;
public final static int LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
public final static int VERTICAL_INDEX_SHIFT = 6;
public final static int FLAG_SHIFT = 5;
public final static int GEN_TYPE_SHIFT = 2;
public final static int VOID_SHIFT = 1;
public final static int EXISTENCE_SHIFT = 0;
public final static long ALPHA_MASK = 0b1111;
public final static long RED_MASK = 0b1111_1111;
public final static long GREEN_MASK = 0b1111_1111;
public final static long BLUE_MASK = 0b1111_1111;
public final static long COLOR_MASK = 0b11111111_11111111_11111111;
public final static long HEIGHT_MASK = 0b11_1111_1111;
public final static long DEPTH_MASK = 0b11_1111_1111;
public final static long LIGHTS_MASK = 0b1111_1111;
public final static long BLOCK_LIGHT_MASK = 0b1111;
public final static long SKY_LIGHT_MASK = 0b1111;
public final static long VERTICAL_INDEX_MASK = 0b11;
public final static long FLAG_MASK = 0b1;
public final static long GEN_TYPE_MASK = 0b111;
public final static long VOID_MASK = 1;
public final static long EXISTENCE_MASK = 1;
public static long createVoidDataPoint(int generationMode)
{
long dataPoint = 0;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
dataPoint += VOID_MASK << VOID_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
}
public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode)
{
return createDataPoint(
ColorUtil.getAlpha(color),
ColorUtil.getRed(color),
ColorUtil.getGreen(color),
ColorUtil.getBlue(color),
height, depth, lightSky, lightBlock, generationMode);
}
public static long createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode)
{
long dataPoint = 0;
dataPoint += ((alpha & ALPHA_MASK) >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT;
dataPoint += (red & RED_MASK) << RED_SHIFT;
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT;
dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT;
dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT;
dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT;
dataPoint += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
dataPoint += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
}
public static short getHeight(long dataPoint)
{
return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(long dataPoint)
{
return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getAlpha(long dataPoint)
{
return (short) (((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT);
}
public static short getRed(long dataPoint)
{
return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
{
return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
{
return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK);
}
public static int getLightSky(long dataPoint)
{
return (int) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static int getLightBlock(long dataPoint)
{
return (int) ((dataPoint >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
public static byte getGenerationMode(long dataPoint)
{
return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
}
public static boolean isItVoid(long dataPoint)
{
return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1);
}
public static boolean doesItExist(long dataPoint)
{
return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
}
public static int getColor(long dataPoint)
{
int color = getBlue(dataPoint) << BLUE_COLOR_SHIFT;
color += getRed(dataPoint) << BLUE_COLOR_SHIFT;
return (int) (dataPoint >>> COLOR_SHIFT);
}
public static int getLightColor(long dataPoint, boolean roof, boolean day)
{
int lightBlock = getLightBlock(dataPoint);
int lightSky = getLightSky(dataPoint);
int lightTint = LightTexture.pack(lightSky,lightBlock);
int red = (ColorUtil.getRed(lightTint) + getRed(dataPoint))/2;
int green = (ColorUtil.getGreen(lightTint) + getGreen(dataPoint))/2;
int blue = (ColorUtil.getBlue(lightTint) + getBlue(dataPoint))/2;
/*
red = LodUtil.clamp(0, getRed(dataPoint) + red, 255);
green = LodUtil.clamp(0, getGreen(dataPoint) + green, 255);
blue = LodUtil.clamp(0, getBlue(dataPoint) + blue, 255);*/
return ColorUtil.rgbToInt(red, green, blue);
}
public static String toString(long dataPoint)
{
StringBuilder s = new StringBuilder();
s.append(getHeight(dataPoint));
s.append(" ");
s.append(getDepth(dataPoint));
s.append(" ");
s.append(getAlpha(dataPoint));
s.append(" ");
s.append(getRed(dataPoint));
s.append(" ");
s.append(getBlue(dataPoint));
s.append(" ");
s.append(getGreen(dataPoint));
s.append(" ");
s.append(getLightBlock(dataPoint));
s.append(" ");
s.append(getLightSky(dataPoint));
s.append(" ");
s.append(getGenerationMode(dataPoint));
s.append(" ");
s.append(isItVoid(dataPoint));
s.append(" ");
s.append(doesItExist(dataPoint));
s.append('\n');
return s.toString();
}
public static long mergeSingleData(long[] dataToMerge)
{
int numberOfChildren = 0;
int numberOfVoidChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempHeight = 0;
int tempDepth = 0;
int tempLightBlock = 0;
int tempLightSky = 0;
byte tempGenMode = DistanceGenerationMode.SERVER.complexity;
boolean allEmpty = true;
boolean allVoid = true;
for (long data : dataToMerge)
{
if (DataPointUtil.doesItExist(data))
{
allEmpty = false;
if (!(DataPointUtil.isItVoid(data)))
{
numberOfChildren++;
allVoid = false;
tempAlpha += DataPointUtil.getAlpha(data);
tempRed += DataPointUtil.getRed(data);
tempGreen += DataPointUtil.getGreen(data);
tempBlue += DataPointUtil.getBlue(data);
tempHeight += DataPointUtil.getHeight(data);
tempDepth += DataPointUtil.getDepth(data);
tempLightBlock += DataPointUtil.getLightBlock(data);
tempLightSky += DataPointUtil.getLightSky(data);
}
tempGenMode = (byte) Math.min(tempGenMode, DataPointUtil.getGenerationMode(data));
} else
{
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
}
}
if (allEmpty)
{
//no child has been initialized
return DataPointUtil.EMPTY_DATA;
} else if (allVoid)
{
//all the children are void
return DataPointUtil.createVoidDataPoint(tempGenMode);
} else
{
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempHeight = tempHeight / numberOfChildren;
tempDepth = tempDepth / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
return DataPointUtil.createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, tempHeight, tempDepth, tempLightSky, tempLightBlock, tempGenMode);
}
}
public static long[] mergeVerticalData(long[][] dataToMerge)
{
boolean[] projection = ThreadMapUtil.getProjection(WORLD_HEIGHT + 1);
int[][] heightAndDepth = ThreadMapUtil.getHeightAndDepth(WORLD_HEIGHT + 1);
long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(dataToMerge.length);
int genMode = DistanceGenerationMode.SERVER.complexity;
boolean allEmpty = true;
boolean allVoid = true;
long singleData;
for(int k=0; k < projection.length; k++)
projection[k] = false;
int depth = 0;
int height = 0;
//We collect the indexes of the data, ordered by the depth
for (int index = 0; index < dataToMerge.length; index++)
{
for (int dataIndex = 0; dataIndex < dataToMerge[index].length; dataIndex++)
{
singleData = dataToMerge[index][dataIndex];
if (doesItExist(singleData))
{
genMode = Math.min(genMode, getGenerationMode(singleData));
allEmpty = false;
if (!isItVoid(singleData))
{
allVoid = false;
depth = getDepth(singleData);
height = getHeight(singleData);
for (int y = depth; y <= height; y++)
{
projection[y] = true;
}
}
}
}
}
//We check if there is any data that's not empty or void
if (allEmpty)
{
return new long[]{EMPTY_DATA};
}
if (allVoid)
{
return new long[]{createVoidDataPoint(genMode)};
}
int count = 0;
int i = 0;
while (i < projection.length)
{
while (i < projection.length && !projection[i])
{
i++;
}
depth = i;
while (i < projection.length && projection[i])
{
height = i;
i++;
}
if(!(i < projection.length))
break;
heightAndDepth[count][0] = depth;
heightAndDepth[count][1] = height;
count++;
}
//As standard the vertical lods are ordered from top to bottom
long[] dataPoint = new long[count];
for (int j = count - 1; j >= 0; j--)
{
depth = heightAndDepth[j][0];
height = heightAndDepth[j][1];
for(int k = 0; k < dataToMerge.length; k++){
singleDataToMerge[k] = 0;
}
for (int index = 0; index < dataToMerge.length; index++)
{
for (int dataIndex = 0; dataIndex < dataToMerge[index].length; dataIndex++)
{
singleData = dataToMerge[index][dataIndex];
if (doesItExist(singleData) && !isItVoid(singleData))
{
if ((depth <= getDepth(singleData) && getDepth(singleData) <= height)
|| (depth <= getHeight(singleData) && getHeight(singleData) <= height))
{
if(getHeight(singleData) > getHeight(singleDataToMerge[index]))
{
singleDataToMerge[index] = singleData;
}
}
}
}
}
long data = mergeSingleData(singleDataToMerge);
dataPoint[j] = createDataPoint(height, depth, getColor(data), getLightSky(data), getLightBlock(data), getGenerationMode(data));
}
return dataPoint;
}
public static long[] compress(long[] data, byte detailLevel)
{
return null;
}
}
@@ -19,6 +19,19 @@ public class DetailDistanceUtil
private static int base = 2;
private static double logBase = Math.log(2);
private static int[] maxVerticalData = {
8,
4,
4,
2,
2,
1,
1,
1,
1,
1,
1,};
private static LodDetail[] lodGenDetails = {
LodDetail.FULL,
LodDetail.HALF,
@@ -147,7 +160,13 @@ public class DetailDistanceUtil
public static byte getLodDrawDetail(int detail)
{
return (byte) Math.max(detail, minDrawDetail);
if (detail < minGenDetail)
{
return lodGenDetails[minGenDetail].detailLevel;
} else
{
return lodGenDetails[detail].detailLevel;
}
}
public static LodDetail getLodGenDetail(int detail)
@@ -176,6 +195,10 @@ public class DetailDistanceUtil
}
}
public static int getMaxVerticalData(int detail)
{
return maxVerticalData[LodUtil.clamp(minGenDetail, detail, LodUtil.REGION_DETAIL_LEVEL)];
}
public static boolean regionInView(int playerPosX, int playerPosY, int playerPosZ, int xRot, int yRot, int fov, RegionPos regionPos)
{
@@ -1,4 +1,4 @@
package com.seibel.lod.objects;
package com.seibel.lod.util;
import com.seibel.lod.util.LodUtil;
+10 -6
View File
@@ -21,7 +21,6 @@ import java.awt.Color;
import java.io.File;
import java.util.HashSet;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.wrappers.MinecraftWrapper;
@@ -64,7 +63,10 @@ public class LodUtil
* and/or add a method to generate colors based on texture
* issue #64 */
public static final int STONE_COLOR_INT = LodUtil.colorToInt(new Color(150, 150, 150));
public static final int NETHERRACK_COLOR_INT = LodUtil.colorToInt(new Color(95, 38, 38));
public static final int WARPED_NYLIUM_COLOR_INT = LodUtil.colorToInt(new Color(34, 94, 85));
public static final int CRIMSON_NYLIUM_COLOR_INT = LodUtil.colorToInt(new Color(126, 27, 27));
/**
* In order of nearest to farthest: <br>
* Red, Orange, Yellow, Green, Cyan, Blue, Magenta, white, gray, black
@@ -337,17 +339,19 @@ public class LodUtil
{
if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z))
continue;
/*
long[] dataVertical = lodDim.getData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
long data = dataVertical[dataVertical.length - 1];
long data = lodDim.getData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
short lodAverageHeight = DataPoint.getHeight(data);
short lodAverageHeight = DataPointUtil.getHeight(data);
if (playerPos.getY() <= lodAverageHeight)
{
// don't draw Lod's that are taller than the player
// to prevent LODs being drawn on top of the player
posToSkip.add(new ChunkPos(x, z));
}
}*/
posToSkip.add(new ChunkPos(x, z));
}
}
@@ -0,0 +1,123 @@
package com.seibel.lod.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ThreadMapUtil
{
public static final ConcurrentMap<String,long[]> threadSingleAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadSingleGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadSingleUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[][]> threadBuilderArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[][][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadVerticalAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadVerticalGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[][]> threadVerticalUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,int[]> threadVerticalIndexesMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,boolean[]> projectionMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,int[][]> heightAndDepthMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> singleDataToMergeMap = new ConcurrentHashMap();
public static long[] getSingleAddDataArray(){
if(!threadSingleAddDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleAddDataMap.get(Thread.currentThread().getName()) == null))
{
threadSingleAddDataMap.put(Thread.currentThread().getName(), new long[1]);
}
return threadSingleAddDataMap.get(Thread.currentThread().getName());
}
public static long[] getSingleGetDataArray(){
if(!threadSingleGetDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleGetDataMap.get(Thread.currentThread().getName()) == null))
{
threadSingleGetDataMap.put(Thread.currentThread().getName(), new long[1]);
}
return threadSingleGetDataMap.get(Thread.currentThread().getName());
}
public static long[] getSingleUpdateArray(){
if(!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null))
{
threadSingleUpdateMap.put(Thread.currentThread().getName(), new long[4]);
}
return threadSingleUpdateMap.get(Thread.currentThread().getName());
}
public static long[][] getBuilderArray(){
if(!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[5][];
threadBuilderArrayMap.put(Thread.currentThread().getName(), array);
}
return threadBuilderArrayMap.get(Thread.currentThread().getName());
}
public static long[][][] getBuilderVerticalArray(){
if(!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null))
{
long[][][] array = new long[5][][];
threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array);
}
return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName());
}
public static long[] addVerticalDataArray(){
if(!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[16]);
}
return threadVerticalAddDataMap.get(Thread.currentThread().getName());
}
public static long[] getVerticalGetDataArray(){
if(!threadVerticalGetDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalGetDataMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalGetDataMap.put(Thread.currentThread().getName(), new long[16]);
}
return threadVerticalGetDataMap.get(Thread.currentThread().getName());
}
public static long[][] getVerticalUpdateArray(){
if(!threadVerticalUpdateMap.containsKey(Thread.currentThread().getName()) || (threadVerticalUpdateMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalUpdateMap.put(Thread.currentThread().getName(), new long[4][]);
}
return threadVerticalUpdateMap.get(Thread.currentThread().getName());
}
public static int[] getVerticalIndexesArray(){
if(!threadVerticalIndexesMap.containsKey(Thread.currentThread().getName()) || (threadVerticalIndexesMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalIndexesMap.put(Thread.currentThread().getName(), new int[4]);
}
return threadVerticalIndexesMap.get(Thread.currentThread().getName());
}
public static boolean[] getProjection(int size){
if(!projectionMap.containsKey(Thread.currentThread().getName()) || (projectionMap.get(Thread.currentThread().getName()) == null) || (projectionMap.get(Thread.currentThread().getName()).length != size))
{
projectionMap.put(Thread.currentThread().getName(), new boolean[size]);
}
return projectionMap.get(Thread.currentThread().getName());
}
public static int[][] getHeightAndDepth(int size){
if(!heightAndDepthMap.containsKey(Thread.currentThread().getName()) || (heightAndDepthMap.get(Thread.currentThread().getName()) == null) || (heightAndDepthMap.get(Thread.currentThread().getName()).length != size))
{
heightAndDepthMap.put(Thread.currentThread().getName(), new int[size][2]);
}
return heightAndDepthMap.get(Thread.currentThread().getName());
}
public static long[] getSingleAddDataToMerge(int size){
if(!singleDataToMergeMap.containsKey(Thread.currentThread().getName()) || (singleDataToMergeMap.get(Thread.currentThread().getName()) == null) || (singleDataToMergeMap.get(Thread.currentThread().getName()).length != size))
{
singleDataToMergeMap.put(Thread.currentThread().getName(), new long[size]);
}
return singleDataToMergeMap.get(Thread.currentThread().getName());
}
}