completed the merge method

This commit is contained in:
Morippi
2021-12-14 13:46:10 +01:00
parent 97b2db84cd
commit c45f0b2414
4 changed files with 361 additions and 23 deletions
@@ -11,4 +11,35 @@ public class ColorFormat
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 static int createColorData(int alpha, int red, int green, int blue)
{
int colorData = 0;
colorData += (alpha & ALPHA_MASK) << ALPHA_SHIFT;
colorData += (red & RED_MASK) << RED_SHIFT;
colorData += (green & GREEN_MASK) << GREEN_SHIFT;
colorData += (blue & BLUE_MASK) << BLUE_SHIFT;
return colorData;
}
public static short getAlpha(long dataPoint)
{
return (short) ((dataPoint >>> ALPHA_SHIFT) & ALPHA_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);
}
}
@@ -0,0 +1,29 @@
package com.seibel.lod.core.dataFormat;
public class DataMergeUtil
{
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize)
{
start *= packetSize;
length *= packetSize;
arraySize *= packetSize;
for (int i = 0; i < arraySize - start; i++)
{
array[start + i] = array[start + length + i];
//remove comment to not leave garbage at the end
//array[start + packetSize + i] = 0;
}
}
public static void extendArray(short[] array, int packetSize, int start, int length, int arraySize)
{
start *= packetSize;
length *= packetSize;
arraySize *= packetSize;
for (int i = arraySize - start - 1; i >= 0; i--)
{
array[start + length + i] = array[start + i];
array[start + i] = 0;
}
}
}
@@ -12,27 +12,27 @@ public class LightFormat
public final static byte SKY_LIGHT_MASK = 0b1111;
public byte formatLightAsByte(byte skyLight, byte blockLight)
public static byte formatLightAsByte(byte skyLight, byte blockLight)
{
return (byte) (((skyLight & SKY_LIGHT_MASK) << (BYTE_SKY_LIGHT_SHIFT + 4)) | ((blockLight & BLOCK_LIGHT_MASK) << (BYTE_BLOCK_LIGHT_SHIFT + 4)));
}
public int formatLightAsInt(byte skyLight, byte blockLight)
public static int formatLightAsInt(byte skyLight, byte blockLight)
{
return ((skyLight & SKY_LIGHT_MASK) << INT_SKY_LIGHT_SHIFT) | ((blockLight & BLOCK_LIGHT_MASK) << INT_BLOCK_LIGHT_SHIFT);
}
public int convertByteToIntFormat(byte lights)
public static int convertByteToIntFormat(byte lights)
{
return formatLightAsInt((byte) ((lights >>> BYTE_SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK), (byte) ((lights >>> BYTE_BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK));
}
public byte getSkyLight(byte lights)
public static byte getSkyLight(byte lights)
{
return (byte) ((lights >>> BYTE_SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public byte getBlockLight(byte lights)
public static byte getBlockLight(byte lights)
{
return (byte) ((lights >>> BYTE_BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
@@ -19,14 +19,13 @@
package com.seibel.lod.core.objects.lod;
import com.seibel.lod.core.dataFormat.PositionDataFormat;
import com.seibel.lod.core.dataFormat.VerticalDataFormat;
import com.seibel.lod.core.dataFormat.*;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.util.*;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
/**
*
*
* @author Leonardo Amato
* @version ??
*/
@@ -81,6 +80,7 @@ public class VerticalLevelContainer implements LevelContainer
dataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = data;
return true;
}
@Override
public boolean addVerticalData(long[] data, int posX, int posZ)
{
@@ -101,6 +101,46 @@ public class VerticalLevelContainer implements LevelContainer
return dataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public short getPositionData(int posX, int posZ)
{
return positionDataContainer[posX * size + posZ];
}
public int getVerticalData(int posX, int posZ, int verticalIndex)
{
return verticalDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public int getColorData(int posX, int posZ, int verticalIndex)
{
return colorDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public byte getLightData(int posX, int posZ, int verticalIndex)
{
return lightDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public void setPositionData(short positionData, int posX, int posZ)
{
positionDataContainer[posX * size + posZ] = positionData;
}
public void setVerticalData(int verticalData, int posX, int posZ, int verticalIndex)
{
verticalDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = verticalData;
}
public void setColorData(int colorData, int posX, int posZ, int verticalIndex)
{
colorDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = colorData;
}
public void setLightData(byte lightData, int posX, int posZ, int verticalIndex)
{
lightDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = lightData;
}
@Override
public long getSingleData(int posX, int posZ)
{
@@ -255,22 +295,23 @@ public class VerticalLevelContainer implements LevelContainer
* This method merge column of multiple data together
* @return one column of correctly parsed data
*/
public void mergeAndAddData(int posZ, int posX, short[] inputPositionDataToMerge, int[] inputVerticalData, int[] inputColorData, int[] inputLightData, byte inputDetailLevel, int inputVerticalSize)
public void mergeAndAddData(int posZ, int posX, short[] inputPositionDataToMerge, int[] inputVerticalData, int[] inputColorData, byte[] inputLightData, byte inputDetailLevel, int inputVerticalSize)
{
mergeAndAddData(0, inputPositionDataToMerge.length, posZ, posX, inputPositionDataToMerge, inputVerticalData, inputColorData, inputLightData, inputDetailLevel, inputVerticalSize);
}
/**
* This method merge column of multiple data together
* @return one column of correctly parsed data
*/
public void mergeAndAddData(int sliceStart, int sliceEnd, int posZ, int posX, short[] inputPositionDataToMerge, int[] inputVerticalData, int[] inputColorData, int[] inputLightData, byte inputDetailLevel, int inputVerticalSize)
public void mergeAndAddData(int sliceStart, int sliceEnd, int posZ, int posX, short[] inputPositionData, int[] inputVerticalData, int[] inputColorData, byte[] inputLightData, byte inputDetailLevel, int inputVerticalSize)
{
//STEP 1//
//We initially reset this position of the data container
positionDataContainer[posX * size + posZ] = PositionDataFormat.EMPTY_DATA;
for(int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++)
for (int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++)
{
verticalDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = VerticalDataFormat.EMPTY_LOD;
lightDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = 0;
@@ -289,9 +330,9 @@ public class VerticalLevelContainer implements LevelContainer
short tempPositionData;
//we combine every position in the slice of the input
//I THINK YOU CAN SEE HOW TO USE THE SLICE FROM HERE
for(int index = sliceStart; index <=sliceEnd; index++)
for (int positionIndex = sliceStart; positionIndex <= sliceEnd; positionIndex++)
{
tempPositionData = inputPositionDataToMerge[index];
tempPositionData = inputPositionData[positionIndex];
genMode = (byte) Math.min(genMode, PositionDataFormat.getGenerationMode(tempPositionData));
correctLight &= PositionDataFormat.getFlag(tempPositionData);
allVoid &= PositionDataFormat.isVoid(tempPositionData);
@@ -300,19 +341,20 @@ public class VerticalLevelContainer implements LevelContainer
//Case 1: should never happen but we use this just in case
//if all the data is empty (maybe a bug) then we simply return
if(allEmpty)
if (allEmpty)
{
return;
}
//Case 2: if all the data is void
//if all the data is empty (maybe a bug) then we simply return
if(allVoid)
if (allVoid)
{
positionDataContainer[posX * size + posZ] = PositionDataFormat.createVoidPositionData(genMode);
return;
}
//Case 3: data is non void and non empty, we continue
positionDataContainer[posX * size + posZ] = PositionDataFormat.createPositionData(0, correctLight, genMode);
@@ -334,9 +376,127 @@ public class VerticalLevelContainer implements LevelContainer
*/
int inputSize = 1 << inputDetailLevel;
// I'll disable the ThreadMap array for the initial testing ThreadMapUtil.getHeightAndDepth(inputVerticalSize * 2 * 4)
// I'll disable the ThreadMap array for the initial testing //ThreadMapUtil.getHeightAndDepth(inputVerticalSize * 2 * 4)
short[] heightAndDepth = new short[inputVerticalSize * 2 * 4];
int tempVerticalData;
short depth;
short height;
int count = 0;
int i;
int ii;
//We collect the indexes of the data, ordered by the depth
for (int positionIndex = 0; positionIndex < size; positionIndex++)
{
tempPositionData = inputPositionData[positionIndex];
if (!PositionDataFormat.doesItExist(tempPositionData) || PositionDataFormat.isVoid(tempPositionData))
continue;
for (int verticalIndex = 0; verticalIndex < inputVerticalSize; verticalIndex++)
{
tempVerticalData = inputVerticalData[positionIndex * inputVerticalSize + verticalIndex];
if (VerticalDataFormat.doesItExist(tempVerticalData))
{
depth = VerticalDataFormat.getDepth(tempVerticalData);
height = VerticalDataFormat.getDepth(tempVerticalData);
int botPos = -1;
int topPos = -1;
//values fall in between and possibly require extension of array
boolean botExtend = false;
boolean topExtend = false;
for (i = 0; i < count; i++)
{
if (depth <= heightAndDepth[i * 2] && depth >= heightAndDepth[i * 2 + 1])
{
botPos = i;
break;
}
else if (depth < heightAndDepth[i * 2 + 1] && ((i + 1 < count && depth > heightAndDepth[(i + 1) * 2]) || i + 1 == count))
{
botPos = i;
botExtend = true;
break;
}
}
for (i = 0; i < count; i++)
{
if (height <= heightAndDepth[i * 2] && height >= heightAndDepth[i * 2 + 1])
{
topPos = i;
break;
}
else if (height < heightAndDepth[i * 2 + 1] && ((i + 1 < count && height > heightAndDepth[(i + 1) * 2]) || i + 1 == count))
{
topPos = i;
topExtend = true;
break;
}
}
if (topPos == -1)
{
if (botPos == -1)
{
//whole block falls above
DataMergeUtil.extendArray(heightAndDepth, 2, 0, 1, count);
heightAndDepth[0] = height;
heightAndDepth[1] = depth;
count++;
}
else if (!botExtend)
{
//only top falls above extending it there, while bottom is inside existing
DataMergeUtil.shrinkArray(heightAndDepth, 2, 0, botPos, count);
heightAndDepth[0] = height;
count -= botPos;
}
else
{
//top falls between some blocks, extending those as well
DataMergeUtil.shrinkArray(heightAndDepth, 2, 0, botPos, count);
heightAndDepth[0] = height;
heightAndDepth[1] = depth;
count -= botPos;
}
}
else if (!topExtend)
{
if (!botExtend)
//both top and bottom are within some exiting blocks, possibly merging them
heightAndDepth[topPos * 2 + 1] = heightAndDepth[botPos * 2 + 1];
else
//top falls between some blocks, extending it there
heightAndDepth[topPos * 2 + 1] = depth;
DataMergeUtil.shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
}
else
{
if (!botExtend)
{
//only top is within some exiting block, extending it
topPos++; //to make it easier
heightAndDepth[topPos * 2] = height;
heightAndDepth[topPos * 2 + 1] = heightAndDepth[botPos * 2 + 1];
DataMergeUtil.shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
}
else
{
//both top and bottom are outside existing blocks
DataMergeUtil.shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
DataMergeUtil.extendArray(heightAndDepth, 2, topPos + 1, 1, count);
count++;
heightAndDepth[topPos * 2 + 2] = height;
heightAndDepth[topPos * 2 + 3] = depth;
}
}
}
else
break;
}
}
//STEP 4//
@@ -360,14 +520,132 @@ public class VerticalLevelContainer implements LevelContainer
this way we reduce from verticalSize 3 to verticalSize 2
*/
//we limit the vertical portion to maxVerticalData
int j = 0;
while (count > verticalSize)
{
ii = DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET;
for (i = 0; i < count - 1; i++)
{
if (heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2] <= ii)
{
ii = heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2];
j = i;
}
}
heightAndDepth[j * 2 + 1] = heightAndDepth[(j + 1) * 2 + 1];
for (i = j + 1; i < count - 1; i++)
{
heightAndDepth[i * 2] = heightAndDepth[(i + 1) * 2];
heightAndDepth[i * 2 + 1] = heightAndDepth[(i + 1) * 2 + 1];
}
//System.arraycopy(heightAndDepth, j + 1, heightAndDepth, j, count - j - 1);
count--;
}
short lodCount = 0;
for (j = 0; j < count; j--)
{
height = heightAndDepth[j * 2];
depth = heightAndDepth[j * 2 + 1];
if ((depth == 0 && height == 0) || j >= heightAndDepth.length / 2)
break;
setVerticalData(
VerticalDataFormat.createVerticalData(height, depth, 0, false, false),
posX,
posZ,
lodCount);
lodCount++;
}
//we update the count
setPositionData(
PositionDataFormat.setLodCount(
PositionDataFormat.createPositionData(0, correctLight, genMode),
lodCount),
posX,
posZ);
//STEP 5//
//we now get the top lods on each vertical index and we merge
//the color, the data
//the color, the data and ligth of all of them
boolean allDefault;
int tempColorData;
byte tempLightData;
int storedVerticalData;
int newVerticalData = 0;
int newColorData = 0;
byte newLightData = 0;
//As standard the vertical lods are ordered from top to bottom
for (int verticalIndex = lodCount; verticalIndex >= 0; verticalIndex--)
{
storedVerticalData = getVerticalData(posX, posZ, verticalIndex);
height = VerticalDataFormat.getHeight(storedVerticalData);
depth = VerticalDataFormat.getDepth(storedVerticalData);
if ((depth == 0 && height == 0) || verticalIndex >= heightAndDepth.length / 2)
break;
int numberOfChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempLightBlock = 0;
int tempLightSky = 0;
for (int positionIndex = 0; positionIndex < size; positionIndex++)
{
tempPositionData = inputPositionData[positionIndex];
if (!PositionDataFormat.doesItExist(tempPositionData) || PositionDataFormat.isVoid(tempPositionData))
continue;
for (int inputVerticalIndex = 0; inputVerticalIndex < inputVerticalSize; inputVerticalIndex++)
{
tempVerticalData = inputVerticalData[positionIndex * inputVerticalSize + inputVerticalIndex];
tempColorData = inputColorData[positionIndex * inputVerticalSize + inputVerticalIndex];
tempLightData = inputLightData[positionIndex * inputVerticalSize + inputVerticalIndex];
if (VerticalDataFormat.doesItExist(tempVerticalData))
{
if ((depth <= VerticalDataFormat.getDepth(tempVerticalData) && VerticalDataFormat.getDepth(tempVerticalData) <= height)
|| (depth <= VerticalDataFormat.getHeight(tempVerticalData) && VerticalDataFormat.getHeight(tempVerticalData) <= height))
{
if (VerticalDataFormat.getHeight(tempVerticalData) > VerticalDataFormat.getHeight(newVerticalData))
{
newVerticalData = tempColorData;
newColorData = tempVerticalData;
newLightData = tempLightData;
}
}
}
else
break;
}
numberOfChildren++;
tempAlpha += ColorFormat.getAlpha(newColorData);
tempRed += ColorFormat.getRed(newColorData);
tempGreen += ColorFormat.getGreen(newColorData);
tempBlue += ColorFormat.getBlue(newColorData);
tempLightBlock += LightFormat.getBlockLight(newLightData);
tempLightSky += LightFormat.getSkyLight(newLightData);
}
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
setColorData(ColorFormat.createColorData(tempAlpha, tempRed, tempGreen, tempBlue), posX, posZ, verticalIndex);
setLightData(LightFormat.formatLightAsByte((byte) tempLightSky, (byte) tempLightBlock), posX, posZ, verticalIndex);
}
/*
/* OLD CODE FOR REFERENCE
int size = dataToMerge.length / inputVerticalData;
// We initialize the arrays that are going to be used
@@ -622,9 +900,9 @@ public class VerticalLevelContainer implements LevelContainer
return dataPoint;
*/
}
@Override
}
@Override
public LevelContainer expand()
{
return new VerticalLevelContainer((byte) (getDetailLevel() - 1));
@@ -686,7 +964,7 @@ public class VerticalLevelContainer implements LevelContainer
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
index += 8;
}
if(!DataPointUtil.doesItExist(dataContainer[i]))
if (!DataPointUtil.doesItExist(dataContainer[i]))
allGenerated = false;
}
if (allGenerated)