diff --git a/build.gradle b/build.gradle index 860d930f6..64ad3ee48 100644 --- a/build.gradle +++ b/build.gradle @@ -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')) diff --git a/src/main/java/com/seibel/lod/Main.java b/src/main/java/com/seibel/lod/Main.java new file mode 100644 index 000000000..e51463c7b --- /dev/null +++ b/src/main/java/com/seibel/lod/Main.java @@ -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(); + }*/ + } +} diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index ad24f4f68..7e502783d 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -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; diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index c12985cc2..46100c328 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -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
- * If true we look down from the top of - * the
- * chunk until we find a non-invisible - * block, and then use
- * its color. If false we generate the - * color immediately for
- * each x and z. - * @param config_useBiomeColors
- * If true use biome foliage, water, and - * grass colors,
- * 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; } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java index b44d75756..73d7e2e2d 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java @@ -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(); } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java index 133e544f5..441ddb1a6 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java @@ -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) { diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java index 64880f35c..ffd5ea5b1 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java @@ -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); } diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java index 187fe079e..7f8c991e2 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java @@ -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; diff --git a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java index 6d21d34d5..0df076916 100644 --- a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java @@ -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 diff --git a/src/main/java/com/seibel/lod/objects/DataPoint.java b/src/main/java/com/seibel/lod/objects/DataPoint.java deleted file mode 100644 index 397f23375..000000000 --- a/src/main/java/com/seibel/lod/objects/DataPoint.java +++ /dev/null @@ -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(); - } -} diff --git a/src/main/java/com/seibel/lod/objects/LevelContainer.java b/src/main/java/com/seibel/lod/objects/LevelContainer.java index ffadb459c..94bcd2c36 100644 --- a/src/main/java/com/seibel/lod/objects/LevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/LevelContainer.java @@ -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(); } diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index 2343ff682..127d541f7 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -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); diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index c0d4fbb18..b21efdd06 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -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; } diff --git a/src/main/java/com/seibel/lod/objects/PosToGenerateContainer.java b/src/main/java/com/seibel/lod/objects/PosToGenerateContainer.java index 405ee2b77..2f05f75dc 100644 --- a/src/main/java/com/seibel/lod/objects/PosToGenerateContainer.java +++ b/src/main/java/com/seibel/lod/objects/PosToGenerateContainer.java @@ -1,5 +1,7 @@ package com.seibel.lod.objects; +import com.seibel.lod.util.LevelPosUtil; + public class PosToGenerateContainer { private int playerPosX; diff --git a/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java b/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java index ef056a13d..2ec972613 100644 --- a/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java +++ b/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java @@ -1,5 +1,6 @@ package com.seibel.lod.objects; +import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodUtil; public class PosToRenderContainer diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java new file mode 100644 index 000000000..88984802e --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -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(); + } +} diff --git a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java new file mode 100644 index 000000000..3de5e291b --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java @@ -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 " "; + } +} diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 68f2918a1..551a8ca72 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -101,7 +101,7 @@ public class ClientProxy public void renderLods(float partialTicks) { // only run the first time setup once - if (firstTimeSetupComplete) + if (!firstTimeSetupComplete) { firstFrameSetup(); } diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index 918281b1f..b2601ae00 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -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 diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java new file mode 100644 index 000000000..7df1df24c --- /dev/null +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -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; + } +} \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java b/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java index 860000a17..a98fc9ec5 100644 --- a/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java +++ b/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java @@ -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) { diff --git a/src/main/java/com/seibel/lod/objects/LevelPosUtil.java b/src/main/java/com/seibel/lod/util/LevelPosUtil.java similarity index 99% rename from src/main/java/com/seibel/lod/objects/LevelPosUtil.java rename to src/main/java/com/seibel/lod/util/LevelPosUtil.java index a3cf7628e..af3bc7547 100644 --- a/src/main/java/com/seibel/lod/objects/LevelPosUtil.java +++ b/src/main/java/com/seibel/lod/util/LevelPosUtil.java @@ -1,4 +1,4 @@ -package com.seibel.lod.objects; +package com.seibel.lod.util; import com.seibel.lod.util.LodUtil; diff --git a/src/main/java/com/seibel/lod/util/LodUtil.java b/src/main/java/com/seibel/lod/util/LodUtil.java index 57410a96d..915eb7bab 100644 --- a/src/main/java/com/seibel/lod/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/util/LodUtil.java @@ -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:
* 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)); } } diff --git a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java new file mode 100644 index 000000000..39ea8f798 --- /dev/null +++ b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java @@ -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 threadSingleAddDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadSingleGetDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadSingleUpdateMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadBuilderArrayMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadBuilderVerticalArrayMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalGetDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalUpdateMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalIndexesMap = new ConcurrentHashMap(); + + + public static final ConcurrentMap projectionMap = new ConcurrentHashMap(); + public static final ConcurrentMap heightAndDepthMap = new ConcurrentHashMap(); + public static final ConcurrentMap 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()); + } +}