diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index e7804012f..5216effdc 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -41,11 +41,20 @@ import com.seibel.lod.util.LodUtil; import com.seibel.lod.util.ThreadMapUtil; import com.seibel.lod.wrappers.MinecraftWrapper; -import net.minecraft.block.*; +import net.minecraft.block.AbstractPlantBlock; +import net.minecraft.block.AbstractTopPlantBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.BushBlock; +import net.minecraft.block.FlowerBlock; +import net.minecraft.block.GrassBlock; +import net.minecraft.block.IGrowable; +import net.minecraft.block.LeavesBlock; +import net.minecraft.block.TallGrassBlock; import net.minecraft.block.material.MaterialColor; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.dispenser.IBlockSource; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -59,7 +68,6 @@ import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.chunk.IChunk; import net.minecraft.world.gen.Heightmap; -import net.minecraftforge.client.extensions.IForgeBakedModel; import net.minecraftforge.client.model.data.ModelDataMap; /** @@ -73,9 +81,9 @@ import net.minecraftforge.client.model.data.ModelDataMap; public class LodBuilder { private static MinecraftWrapper mc = MinecraftWrapper.INSTANCE; - + private ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName())); - + public static final Direction[] directions = new Direction[]{Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN}; public static final int CHUNK_DATA_WIDTH = LodUtil.CHUNK_WIDTH; public static final int CHUNK_SECTION_HEIGHT = CHUNK_DATA_WIDTH; @@ -83,9 +91,9 @@ public class LodBuilder public static final ConcurrentMap colorMap = new ConcurrentHashMap<>(); public static final ConcurrentMap toTint = new ConcurrentHashMap<>(); public static final ConcurrentMap shapeMap = new ConcurrentHashMap<>(); - + public static final ModelDataMap dataMap = new ModelDataMap.Builder().build(); - + /** * If no blocks are found in the area in determineBottomPointForArea return this */ @@ -94,34 +102,34 @@ public class LodBuilder * If no blocks are found in the area in determineHeightPointForArea return this */ public static final short DEFAULT_HEIGHT = 0; - + /** * How wide LodDimensions should be in regions */ public int defaultDimensionWidthInRegions = 5; - + public LodBuilder() { - + } - + public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world) { generateLodNodeAsync(chunk, lodWorld, world, DistanceGenerationMode.SERVER); } - - + + public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world, DistanceGenerationMode generationMode) { if (lodWorld == null || !lodWorld.getIsWorldLoaded()) return; - + // don't try to create an LOD object // if for some reason we aren't // given a valid chunk object if (chunk == null) return; - + Thread thread = new Thread(() -> { try @@ -130,11 +138,11 @@ public class LodBuilder // get the textures for blocks if (mc.getClientWorld() == null) return; - + DimensionType dim = world.dimensionType(); - + LodDimension lodDim; - + int playerPosX; int playerPosZ; if (mc.getPlayer() == null) @@ -167,7 +175,7 @@ public class LodBuilder }); lodGenThreadPool.execute(thread); } - + /** * Creates a LodChunk for a chunk in the given world. * @@ -177,7 +185,7 @@ public class LodBuilder { generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig()); } - + /** * Creates a LodChunk for a chunk in the given world. * @@ -188,7 +196,7 @@ public class LodBuilder { if (chunk == null) throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); - + int startX; int startZ; int endX; @@ -201,7 +209,7 @@ public class LodBuilder return; byte minDetailLevel = region.getMinDetailLevel(); detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel); - + VerticalQuality verticalQuality = LodConfig.CLIENT.worldGenerator.lodQualityMode.get(); byte detailLevel = detail.detailLevel; int posX; @@ -212,46 +220,46 @@ public class LodBuilder startZ = detail.startZ[i]; endX = detail.endX[i]; endZ = detail.endZ[i]; - + 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; switch (verticalQuality) { - default: - case HEIGHTMAP: - long singleData; - long[] dataToMergeSingle = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); - singleData = DataPointUtil.mergeSingleData(dataToMergeSingle); - lodDim.addData(detailLevel, - posX, - posZ, - 0, - singleData, - false); - break; - case MULTI_LOD: - long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); - data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight, DetailDistanceUtil.getMaxVerticalData(detailLevel)); - - - //lodDim.clear(detailLevel, posX, posZ); - if (data != null && data.length != 0) + default: + case HEIGHTMAP: + long singleData; + long[] dataToMergeSingle = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); + singleData = DataPointUtil.mergeSingleData(dataToMergeSingle); + lodDim.addData(detailLevel, + posX, + posZ, + 0, + singleData, + false); + break; + case MULTI_LOD: + long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); + data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight, DetailDistanceUtil.getMaxVerticalData(detailLevel)); + + + //lodDim.clear(detailLevel, posX, posZ); + if (data != null && data.length != 0) + { + for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++) { - for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++) - { - - if (!DataPointUtil.doesItExist(data[verticalIndex])) - break; - lodDim.addData(detailLevel, - posX, - posZ, - verticalIndex, - data[verticalIndex], - false); - } + + if (!DataPointUtil.doesItExist(data[verticalIndex])) + break; + lodDim.addData(detailLevel, + posX, + posZ, + verticalIndex, + data[verticalIndex], + false); } - break; + } + break; } } lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z); @@ -260,23 +268,23 @@ public class LodBuilder e.printStackTrace(); throw e; } - + } - + private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { int size = 1 << detail.detailLevel; - + long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray()[detail.detailLevel]; - + if (dataToMerge == null || dataToMerge.length != size * size * DataPointUtil.worldHeight + 1) dataToMerge = new long[size * size * DataPointUtil.worldHeight + 1]; - + for (int i = 0; i < dataToMerge.length; i++) dataToMerge[i] = DataPointUtil.EMPTY_DATA; - + int verticalData = DataPointUtil.worldHeight; - + ChunkPos chunkPos = chunk.getPos(); int height; int depth; @@ -285,7 +293,7 @@ public class LodBuilder int lightSky; int lightBlock; int generation = config.distanceGenerationMode.complexity; - + int xRel; int zRel; int xAbs; @@ -293,17 +301,17 @@ public class LodBuilder int zAbs; boolean hasCeiling = mc.getClientWorld().dimensionType().hasCeiling(); boolean hasSkyLight = mc.getClientWorld().dimensionType().hasSkyLight(); - + BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0); int index; - + 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 yAbs = DataPointUtil.worldHeight + 2; int count = 0; @@ -318,7 +326,7 @@ public class LodBuilder dataToMerge[index * verticalData] = DataPointUtil.createVoidDataPoint(generation); break; } - + yAbs = height - 1; // We search light on above air block depth = determineBottomPointFrom(chunk, config, xRel, zRel, yAbs, blockPos); @@ -338,8 +346,8 @@ public class LodBuilder } lightBlock = light & 0b1111; lightSky = (light >> 4) & 0b1111; - - + + dataToMerge[index * verticalData + count] = DataPointUtil.createDataPoint(height, depth, color, lightSky, lightBlock, generation); topBlock = false; yAbs = depth - 1; @@ -348,7 +356,7 @@ public class LodBuilder } return dataToMerge; } - + /** * Find the lowest valid point from the bottom. */ @@ -384,7 +392,7 @@ public class LodBuilder } return depth; } - + /** * Find the highest valid point from the Top */ @@ -418,19 +426,19 @@ public class LodBuilder } return height; } - + private long[] createSingleDataToMerge(HorizontalResolution 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; @@ -438,10 +446,10 @@ public class LodBuilder int zAbs; int lightBlock; int lightSky; - + boolean hasCeiling = mc.getClientWorld().dimensionType().hasCeiling(); boolean hasSkyLight = mc.getClientWorld().dimensionType().hasSkyLight(); - + BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0); int index = 0; if (dataToMerge == null) @@ -454,23 +462,23 @@ public class LodBuilder 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, blockPos); depth = determineBottomPoint(chunk, config, xRel, zRel, blockPos); - + blockPos.set(xAbs, yAbs + 1, zAbs); light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, true); lightBlock = light & 0b1111; @@ -483,7 +491,7 @@ public class LodBuilder // =====================// // constructor helpers // // =====================// - + /** * Find the lowest valid point from the bottom. */ @@ -517,8 +525,8 @@ public class LodBuilder } return depth; } - - + + /** * Find the highest valid point from the Top */ @@ -552,7 +560,7 @@ public class LodBuilder } return height; } - + /** * Generate the color for the given chunk using biome water color, foliage * color, and grass color. @@ -574,7 +582,7 @@ public class LodBuilder if (chunkSections[sectionIndex] != null) { // the bit shift is equivalent to dividing by 4 - + blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel); //colorInt = getColorTextureForBlock(blockState, blockPos); colorInt = getColorForBlock(chunk, blockPos); @@ -587,25 +595,25 @@ public class LodBuilder } return colorInt; } - + private int getLightValue(IChunk chunk, BlockPos.Mutable blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock) { int skyLight; int blockLight = 0; if (mc.getClientWorld() == null) return 0; - + IWorld world = mc.getClientWorld(); - + //int blockBrightness = world.getBrightness(LightType.BLOCK, blockPos); int blockBrightness = chunk.getLightEmission(blockPos); - + if (hasCeiling && topBlock) blockPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ()); else blockPos.set(blockPos.getX(), blockPos.getY() + 1, blockPos.getZ()); - - + + if (!hasSkyLight && hasCeiling) { skyLight = 0; @@ -631,18 +639,18 @@ public class LodBuilder } blockLight = world.getBrightness(LightType.BLOCK, blockPos); blockLight = LodUtil.clamp(0, blockLight + blockBrightness, 15); - + return blockLight + (skyLight << 4); } - - + + private int getColorTextureForBlock(BlockState blockState, BlockPos blockPos, boolean topTextureRequired) { Block block = blockState.getBlock(); if (colorMap.containsKey(block) && toTint.containsKey(block)) return colorMap.get(block); - - + + World world = mc.getClientWorld(); TextureAtlasSprite texture; List quad = null; @@ -659,7 +667,7 @@ public class LodBuilder toTint.put(block, quad.get(0).isTinted()); } else toTint.put(blockState.getBlock(), false); - + if (topTextureRequired && !quad.isEmpty()) { texture = quad.get(0).getSprite(); @@ -667,8 +675,8 @@ public class LodBuilder { texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos); } - - + + int count = 0; int alpha = 0; int red = 0; @@ -716,37 +724,37 @@ public class LodBuilder } if (blockState.getBlock().equals(Blocks.TALL_GRASS)) System.out.println(ColorUtil.toString(color) + " " + numberOfGreyPixel + " " + count); - if (block instanceof TallGrassBlock || (couldHaveGrassTint(block) || couldHaveLeavesTint(block) || couldHaveWaterTint(block)) && (float) (numberOfGreyPixel / count) > 0.75f) + if (block instanceof TallGrassBlock || (couldHaveGrassTint(block) || couldHaveLeavesTint(block) || couldHaveWaterTint(block)) && numberOfGreyPixel / count > 0.75f) { toTint.replace(block, true); } colorMap.put(block, color); - + return color; } - + private boolean couldHaveGrassTint(Block block) { return block instanceof GrassBlock - || block instanceof BushBlock - || block instanceof IGrowable - || block instanceof AbstractPlantBlock - || block instanceof AbstractTopPlantBlock - || block instanceof TallGrassBlock; + || block instanceof BushBlock + || block instanceof IGrowable + || block instanceof AbstractPlantBlock + || block instanceof AbstractTopPlantBlock + || block instanceof TallGrassBlock; } - + private boolean couldHaveLeavesTint(Block block) { return block instanceof LeavesBlock - || block == Blocks.VINE - || block == Blocks.SUGAR_CANE; + || block == Blocks.VINE + || block == Blocks.SUGAR_CANE; } - + private boolean couldHaveWaterTint(Block block) { return block == Blocks.WATER; } - + /** * Returns a color int for the given block. */ @@ -759,22 +767,22 @@ public class LodBuilder int z = blockPos.getZ(); Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2); int blockColor; - + BlockState blockState = chunk.getBlockState(blockPos); int colorInt = 0; - - + + // block special cases // TODO: this needs to be replaced by a config file of some sort if (blockState == Blocks.AIR.defaultBlockState() - || blockState == Blocks.CAVE_AIR.defaultBlockState() - || blockState == Blocks.BARRIER.defaultBlockState()) + || blockState == Blocks.CAVE_AIR.defaultBlockState() + || blockState == Blocks.BARRIER.defaultBlockState()) { Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z)); tmp = tmp.darker(); colorInt = LodUtil.colorToInt(tmp); } - + blockColor = getColorTextureForBlock(blockState, blockPos, true); if (toTint.get(blockState.getBlock()).booleanValue()) { @@ -799,94 +807,94 @@ public class LodBuilder } return colorInt; } - + /** * Returns a color int for the given biome. */ private int getColorForBiome(int x, int z, Biome biome) { int colorInt; - + switch (biome.getBiomeCategory()) { - - case NETHER: - colorInt = LodUtil.NETHERRACK_COLOR_INT; - break; - - case THEEND: - colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col; - break; - - case BEACH: - case DESERT: - colorInt = Blocks.SAND.defaultBlockState().materialColor.col; - break; - - case EXTREME_HILLS: - colorInt = Blocks.STONE.defaultMaterialColor().col; - break; - - case MUSHROOM: - colorInt = MaterialColor.COLOR_LIGHT_GRAY.col; - break; - - case ICY: - colorInt = Blocks.SNOW.defaultMaterialColor().col; - break; - - case MESA: - colorInt = Blocks.RED_SAND.defaultMaterialColor().col; - break; - - case OCEAN: - case RIVER: - colorInt = biome.getWaterColor(); - break; - - case NONE: - case FOREST: - case TAIGA: - case JUNGLE: - case PLAINS: - case SAVANNA: - case SWAMP: - default: - Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z)); - tmp = tmp.darker(); - colorInt = LodUtil.colorToInt(tmp); - break; - + + case NETHER: + colorInt = LodUtil.NETHERRACK_COLOR_INT; + break; + + case THEEND: + colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col; + break; + + case BEACH: + case DESERT: + colorInt = Blocks.SAND.defaultBlockState().materialColor.col; + break; + + case EXTREME_HILLS: + colorInt = Blocks.STONE.defaultMaterialColor().col; + break; + + case MUSHROOM: + colorInt = MaterialColor.COLOR_LIGHT_GRAY.col; + break; + + case ICY: + colorInt = Blocks.SNOW.defaultMaterialColor().col; + break; + + case MESA: + colorInt = Blocks.RED_SAND.defaultMaterialColor().col; + break; + + case OCEAN: + case RIVER: + colorInt = biome.getWaterColor(); + break; + + case NONE: + case FOREST: + case TAIGA: + case JUNGLE: + case PLAINS: + case SAVANNA: + case SWAMP: + default: + Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z)); + tmp = tmp.darker(); + colorInt = LodUtil.colorToInt(tmp); + break; + } - + return colorInt; } - + /** * Is the layer between the given X, Z, and dataIndex values a valid LOD point? */ private boolean isLayerValidLodPoint(IChunk chunk, BlockPos.Mutable blockPos) { - + BlockState blockState = chunk.getBlockState(blockPos); boolean onlyUseFullBlock = false; boolean avoidSmallBlock = false; if (blockState != null) { //blockState.isCollisionShapeFullBlock(chunk, blockPos); - + if (avoidSmallBlock || onlyUseFullBlock) { if (!blockState.getFluidState().isEmpty()) { return true; } - + VoxelShape voxelShape; if (shapeMap.containsKey(blockState.getBlock())) { voxelShape = shapeMap.get(blockState.getBlock()); - + } else { voxelShape = blockState.getShape(chunk, blockPos); @@ -911,10 +919,10 @@ public class LodBuilder return false; } } - + return blockState.getBlock() != Blocks.AIR - && blockState.getBlock() != Blocks.CAVE_AIR - && blockState.getBlock() != Blocks.BARRIER; + && blockState.getBlock() != Blocks.CAVE_AIR + && blockState.getBlock() != Blocks.BARRIER; } return false; } diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java index 6ec2a0509..ba0bf0dd2 100644 --- a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -1,31 +1,35 @@ package com.seibel.lod.objects; -import com.seibel.lod.util.*; - -import javax.xml.crypto.Data; import java.util.Arrays; +import com.seibel.lod.util.DataPointUtil; +import com.seibel.lod.util.LevelPosUtil; +import com.seibel.lod.util.LodUtil; +import com.seibel.lod.util.ThreadMapUtil; + public class SingleLevelContainer implements LevelContainer { public final byte detailLevel; public final int size; - + public final long[][] dataContainer; - + public SingleLevelContainer(byte detailLevel) { this.detailLevel = detailLevel; size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); dataContainer = new long[size][size]; } - + + @Override public void clear(int posX, int posZ) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); dataContainer[posX][posZ] = DataPointUtil.EMPTY_DATA; } - + + @Override public boolean addData(long data, int posX, int posZ, int index) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -33,7 +37,8 @@ public class SingleLevelContainer implements LevelContainer dataContainer[posX][posZ] = data; return true; } - + + @Override public boolean addSingleData(long newData, int posX, int posZ) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -41,7 +46,8 @@ public class SingleLevelContainer implements LevelContainer dataContainer[posX][posZ] = newData; return true; } - + + @Override public long getData(int posX, int posZ, int index) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -49,7 +55,8 @@ public class SingleLevelContainer implements LevelContainer //Improve this using a thread map to long[] return dataContainer[posX][posZ]; } - + + @Override public long getSingleData(int posX, int posZ) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -57,17 +64,19 @@ public class SingleLevelContainer implements LevelContainer //Improve this using a thread map to long[] return dataContainer[posX][posZ]; } - + + @Override public byte getDetailLevel() { return detailLevel; } - + + @Override public LevelContainer expand() { return new SingleLevelContainer((byte) (getDetailLevel() - 1)); } - + public SingleLevelContainer(byte[] inputData) { int tempIndex; @@ -97,16 +106,17 @@ public class SingleLevelContainer implements LevelContainer index = index + 8; } dataContainer[x][z] = newData; - + } } } - + + @Override public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) { //We reset the array long[] dataToMerge = ThreadMapUtil.getSingleUpdateArray(); - + int childPosX; int childPosZ; long data; @@ -124,12 +134,14 @@ public class SingleLevelContainer implements LevelContainer data = DataPointUtil.mergeSingleData(dataToMerge); addSingleData(data, posX, posZ); } - + + @Override public int getMaxVerticalData() { return 1; } - + + @Override public boolean doesItExist(int posX, int posZ) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -137,7 +149,8 @@ public class SingleLevelContainer implements LevelContainer //Improve this using a thread map to long[] return DataPointUtil.doesItExist(getSingleData(posX, posZ)); } - + + @Override public byte[] toDataString() { int index = 0; @@ -171,7 +184,7 @@ public class SingleLevelContainer implements LevelContainer } return Arrays.copyOfRange(tempData, 0, index); } - + @Override public String toString() { @@ -179,13 +192,15 @@ public class SingleLevelContainer implements LevelContainer stringBuilder.append(detailLevel); return stringBuilder.toString(); } - - + + + @Override public int getMaxNumberOfLods() { return size * size * getMaxVerticalData(); } - + + @Override public int getMaxMemoryUse() { return getMaxNumberOfLods() * 2; //2 byte diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java index 3ef2f7f41..bf6652081 100644 --- a/src/main/java/com/seibel/lod/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -32,21 +32,21 @@ public class DataPointUtil //public final static int MIN_HEIGHT = -64; public final static int EMPTY_DATA = 0; public static int worldHeight = 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; @@ -57,7 +57,7 @@ public class DataPointUtil 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; @@ -73,8 +73,8 @@ public class DataPointUtil 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; @@ -83,7 +83,7 @@ public class DataPointUtil 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( @@ -93,7 +93,7 @@ public class DataPointUtil 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; @@ -109,71 +109,71 @@ public class DataPointUtil 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 isVoid(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, NativeImage lightMap) { int lightBlock = getLightBlock(dataPoint); @@ -182,10 +182,10 @@ public class DataPointUtil int red = ColorUtil.getBlue(color); int green = ColorUtil.getGreen(color); int blue = ColorUtil.getRed(color); - + return ColorUtil.multiplyRGBcolors(getColor(dataPoint), ColorUtil.rgbToInt(red, green, blue)); } - + public static String toString(long dataPoint) { StringBuilder s = new StringBuilder(); @@ -213,11 +213,11 @@ public class DataPointUtil s.append('\n'); return s.toString(); } - + public static long mergeSingleData(long[] dataToMerge) { int numberOfChildren = 0; - + int tempAlpha = 0; int tempRed = 0; int tempGreen = 0; @@ -253,7 +253,7 @@ public class DataPointUtil tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity); } } - + if (allEmpty) { //no child has been initialized @@ -274,46 +274,46 @@ public class DataPointUtil return DataPointUtil.createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, tempHeight, tempDepth, tempLightSky, tempLightBlock, tempGenMode); } } - + public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData) { int size = dataToMerge.length / inputVerticalData; - + //We initialise the arrays that are going to be used short[] projection = ThreadMapUtil.getProjectionShort(); short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth(); long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(); long[] dataPoint = ThreadMapUtil.verticalDataArray(); - + if (projection == null || projection.length != (worldHeight) / 16 + 1) projection = new short[(worldHeight) / 16 + 1]; else Arrays.fill(projection, (short) 0); - + if (heightAndDepth == null || heightAndDepth.length != (worldHeight + 1) * 2) heightAndDepth = new short[(worldHeight + 1) * 2]; else Arrays.fill(heightAndDepth, (short) 0); - + if (singleDataToMerge == null || singleDataToMerge.length != size) singleDataToMerge = new long[size]; else Arrays.fill(singleDataToMerge, EMPTY_DATA); - + if (dataPoint == null || dataPoint.length != worldHeight + 1) dataPoint = new long[worldHeight + 1]; else Arrays.fill(dataPoint, EMPTY_DATA); - + int genMode = DistanceGenerationMode.SERVER.complexity; boolean allEmpty = true; boolean allVoid = true; long singleData; - - + + short depth; short height; - + //We collect the indexes of the data, ordered by the depth for (int index = 0; index < size; index++) { @@ -362,7 +362,7 @@ public class DataPointUtil continue; } depth = (short) (i * 16 + ii); - + while (ii < 15 && ((projection[i] >>> ii) & 1) == 1) ii++; if (ii >= 15 && ((projection[i] >>> ii) & 1) == 1) //if end is not in this chunk { @@ -382,7 +382,7 @@ public class DataPointUtil heightAndDepth[count * 2 + 1] = height; count++; } - + //we limit the vertical portion to maxVerticalData int j = 0; while (count > maxVerticalData) @@ -424,7 +424,7 @@ public class DataPointUtil if (doesItExist(singleData) && !isVoid(singleData)) { if ((depth <= getDepth(singleData) && getDepth(singleData) <= height) - || (depth <= getHeight(singleData) && getHeight(singleData) <= height)) + || (depth <= getHeight(singleData) && getHeight(singleData) <= height)) { if (getHeight(singleData) > getHeight(singleDataToMerge[index])) { @@ -435,12 +435,12 @@ public class DataPointUtil } } long data = mergeSingleData(singleDataToMerge); - + dataPoint[count - j - 1] = createDataPoint(height, depth, getColor(data), getLightSky(data), getLightBlock(data), getGenerationMode(data)); } return dataPoint; } - + public static long[] compress(long[] data, byte detailLevel) { return null;