Add variable detail LODs

This commit is contained in:
James Seibel
2021-06-12 18:19:45 -05:00
parent bf6db89a4b
commit 3694dcba4c
9 changed files with 554 additions and 422 deletions
+238 -155
View File
@@ -3,6 +3,9 @@ package com.seibel.lod.objects;
import java.awt.Color;
import com.seibel.lod.enums.ColorDirection;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.handlers.LodDimensionFileHandler;
import com.seibel.lod.util.LodConfig;
import net.minecraft.util.math.ChunkPos;
@@ -11,7 +14,7 @@ import net.minecraft.util.math.ChunkPos;
* and color data for an LOD object.
*
* @author James Seibel
* @version 05-29-2021
* @version 6-12-2021
*/
public class LodChunk
{
@@ -19,39 +22,29 @@ public class LodChunk
private static final int DATA_DELIMITER_COUNT = 22;
/** This is what separates each piece of data in the toData method */
public static final char DATA_DELIMITER = ',';
private static final char DATA_DELIMITER = LodDimensionFileHandler.DATA_DELIMITER;
/** Width of a Minecraft Chunk */
public static final int WIDTH = 16;
/** alpha used when drawing chunks in debug mode */
private static final int DEBUG_ALPHA = 255; // 0 - 255
private static final Color DEBUG_BLACK = new Color(0, 0, 0, DEBUG_ALPHA);
private static final Color DEBUG_WHITE = new Color(255, 255, 255, DEBUG_ALPHA);
private static final Color INVISIBLE = new Color(0,0,0,0);
public static final LodDetail DETAIL = LodDetail.QUAD;
/** The x coordinate of the chunk. */
public int x = 0;
/** The z coordinate of the chunk. */
public int z = 0;
/*
* The reason we are only using 1 height and depth point
* instead of multiple is because:
* 1. more points would drastically increase the amount of
* memory and disk space needed
* 2. more height/depth points require more color points,
* which can get out of hand quickly
* 3. with the increased disk space reading/writing would
* take far too long
* 4. the increased resolution is generally not worth it,
* 4 LODs per chunk is the limit of diminishing returns.
* And some of that could potentially be faked through
* smart LodTemplates
*/
private short height;
private short depth;
/** The average color for the 6 cardinal directions */
public Color colors[];
/** This stores the height and color for each data point in the LodChunk */
public LodDataPoint dataPoints[][];
/** If true then this LodChunk contains no data */
private boolean empty = false;
@@ -67,16 +60,11 @@ public class LodChunk
x = 0;
z = 0;
height = 0;
depth = 0;
colors = new Color[ColorDirection.values().length];
// by default have the colors invisible
for(ColorDirection dir : ColorDirection.values())
colors[dir.value] = INVISIBLE;
dataPoints = new LodDataPoint[DETAIL.lengthCount][DETAIL.lengthCount];
}
// TODO
/**
* Creates an LodChunk from the string
* generated by the toData method.
@@ -84,107 +72,107 @@ public class LodChunk
* @throws IllegalArgumentException if the data isn't valid to create a LodChunk
* @throws NumberFormatException if any piece of data can't be converted at any point
*/
public LodChunk(String data) throws IllegalArgumentException, NumberFormatException
{
/*
* data format:
* x, z, height, depth, rgb color data
*
* example:
* 5,8, 4, 0, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255,
*/
// make sure there are the correct number of entries
// in the data string (28)
int count = 0;
for(int i = 0; i < data.length(); i++)
if(data.charAt(i) == DATA_DELIMITER)
count++;
if(count != DATA_DELIMITER_COUNT)
throw new IllegalArgumentException("LodChunk constructor givin an invalid string. The data given had " + count + " delimiters when it should have had " + DATA_DELIMITER_COUNT + ".");
// index we will use when going through the String
int index = 0;
int lastIndex = 0;
// x and z position
index = data.indexOf(DATA_DELIMITER, 0);
x = Integer.parseInt(data.substring(0,index));
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex+1);
z = Integer.parseInt(data.substring(lastIndex+1,index));
// height
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex+1);
height = Short.parseShort(data.substring(lastIndex+1,index));
// depth
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex+1);
depth = Short.parseShort(data.substring(lastIndex+1,index));
// color
colors = new Color[6];
for(ColorDirection dir : ColorDirection.values())
{
int red = 0;
int green = 0;
int blue = 0;
// get r,g,b
for(int i = 0; i < 3; i++)
{
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
String raw = "";
switch(i)
{
case 0:
raw = data.substring(lastIndex+1,index);
red = Short.parseShort(raw);
break;
case 1:
raw = data.substring(lastIndex+1,index);
green = Short.parseShort(raw);
break;
case 2:
raw = data.substring(lastIndex+1,index);
blue = Short.parseShort(raw);
break;
}
}
colors[dir.value] = new Color(red, green, blue);
}
// after going through all this
// is this LOD empty?
empty = determineIfEmtpy();
}
// public LodChunk(String data) throws IllegalArgumentException, NumberFormatException
// {
// /*
// * data format:
// * x, z, height, depth, rgb color data
// *
// * example:
// * 5,8, 4, 0, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255,
// */
//
// // make sure there are the correct number of entries
// // in the data string (28)
// int count = 0;
//
// for(int i = 0; i < data.length(); i++)
// if(data.charAt(i) == DATA_DELIMITER)
// count++;
//
// if(count != DATA_DELIMITER_COUNT)
// throw new IllegalArgumentException("LodChunk constructor givin an invalid string. The data given had " + count + " delimiters when it should have had " + DATA_DELIMITER_COUNT + ".");
//
//
//
// // index we will use when going through the String
// int index = 0;
// int lastIndex = 0;
//
//
//
// // x and z position
// index = data.indexOf(DATA_DELIMITER, 0);
// x = Integer.parseInt(data.substring(0,index));
//
// lastIndex = index;
// index = data.indexOf(DATA_DELIMITER, lastIndex+1);
// z = Integer.parseInt(data.substring(lastIndex+1,index));
//
// // height
// lastIndex = index;
// index = data.indexOf(DATA_DELIMITER, lastIndex+1);
// // TODO
// //height = Short.parseShort(data.substring(lastIndex+1,index));
//
// // depth
// lastIndex = index;
// index = data.indexOf(DATA_DELIMITER, lastIndex+1);
// //depth = Short.parseShort(data.substring(lastIndex+1,index));
//
//
//
// // color
// //colors = new Color[6];
// for(ColorDirection dir : ColorDirection.values())
// {
// int red = 0;
// int green = 0;
// int blue = 0;
//
// // get r,g,b
// for(int i = 0; i < 3; i++)
// {
// lastIndex = index;
// index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
//
// String raw = "";
// switch(i)
// {
// case 0:
// raw = data.substring(lastIndex+1,index);
// red = Short.parseShort(raw);
// break;
// case 1:
// raw = data.substring(lastIndex+1,index);
// green = Short.parseShort(raw);
// break;
// case 2:
// raw = data.substring(lastIndex+1,index);
// blue = Short.parseShort(raw);
// break;
// }
// }
//
// // TODO
// //colors[dir.value] = new Color(red, green, blue);
// }
//
//
// // after going through all this
// // is this LOD empty?
// empty = determineIfEmtpy();
// }
/**
* Create a LodChunk from the given values.
*/
public LodChunk(ChunkPos pos, short newHeight, short newDepth, Color[] newColors)
public LodChunk(ChunkPos pos, LodDataPoint[][] newDataPoints)
{
x = pos.x;
z = pos.z;
height = newHeight;
depth = newDepth;
colors = newColors;
dataPoints = newDataPoints;
empty = determineIfEmtpy();
}
@@ -217,27 +205,30 @@ public class LodChunk
*/
private boolean determineIfEmtpy()
{
// we don't check the depth since the
// height should always be greater than or equal
// to the depth
if(height >= 0)
for(LodDataPoint[] dataPointArray : dataPoints)
{
// the height is valid,
// do we have at least 1 non-invisible color?
for(ColorDirection dir : ColorDirection.values())
if(!colors[dir.value].equals(INVISIBLE))
// at least one direction has a non-invisible color
return false;
return true;
}
else
{
// the height is negative,
// this LodChunk is empty
return true;
for(LodDataPoint dataPoint : dataPointArray)
{
if (dataPoint == null)
continue;
// we don't check the depth since the
// height should always be greater than or equal
// to the depth
if(dataPoint.height >= 0)
{
// the height is valid,
// do we have at least 1 non-invisible color?
for(ColorDirection dir : ColorDirection.values())
if(!dataPoint.colors[dir.value].equals(INVISIBLE))
// at least one direction has a non-invisible color
return false;
}
}
}
// we checked everywhere, this LodChunk is empty
return true;
}
@@ -247,28 +238,124 @@ public class LodChunk
// output //
//========//
/**
* Returns the data point for the given relative block position.
*/
public LodDataPoint getDataPointForBlockPos(int blockX, int blockZ)
{
if (blockX < 0 || blockX > WIDTH || blockX < 0 || blockZ > WIDTH)
throw new IllegalArgumentException("The coordinates given are outside the LodChunk");
return dataPoints[blockX / DETAIL.width][blockZ / DETAIL.width];
}
/** Returns the color for the given direction */
public Color getColor(ColorDirection dir)
public Color getColorForBlockPos(int blockX, int blockZ, ColorDirection dir)
{
return colors[dir.value];
return getDataPointForBlockPos(blockX, blockZ).colors[dir.value];
}
public short getHeight()
public short getHeightForBlockPos(int blockX, int blockZ)
{
return height;
return getDataPointForBlockPos(blockX, blockZ).height;
}
public short getDepth()
public short getDepthForBlockPos(int blockX, int blockZ)
{
return depth;
return getDataPointForBlockPos(blockX, blockZ).depth;
}
/**
* @param startX
* @param startZ
* @param endX
* @param endZ
* @return
*/
public short getAverageHeightOverArea(int startX, int startZ, int endX, int endZ)
{
int average = 0;
for(int x = startX; x < endX; x++)
for(int z = startZ; z < endZ; z++)
average += getHeightForBlockPos(x,z);
return (short) (average / ((endX - startX) * (endZ - startZ)));
}
/**
* @param startX
* @param startZ
* @param endX
* @param endZ
* @return
*/
public short getAverageDepthOverArea(int startX, int startZ, int endX, int endZ)
{
int average = 0;
for(int x = startX; x < endX; x++)
for(int z = startZ; z < endZ; z++)
average += getDepthForBlockPos(x,z);
return (short) (average / ((endX - startX) * (endZ - startZ)));
}
/**
* Determine the color for each side of this LOD.
*/
public Color[] getAverageColorOverArea(int startX, int startZ, int endX, int endZ, boolean debugging)
{
Color[] colors = new Color[ColorDirection.values().length];
for(int x = startX; x < endX; x++)
{
for(int z = startZ; z < endZ; z++)
{
if (!debugging)
{
// if NOT debugging, look to the config to determine
// how this LOD should be colored
switch (LodConfig.CLIENT.lodColorStyle.get())
{
case TOP:
// only add the top's color to the array
for(ColorDirection dir : ColorDirection.values())
colors[dir.value] = getColorForBlockPos(x,z, ColorDirection.TOP);
break;
case INDIVIDUAL_SIDES:
// add each direction's color to the array
for(ColorDirection dir : ColorDirection.values())
colors[dir.value] = getColorForBlockPos(x,z, dir);
break;
}
}
else
{
// if debugging draw the squares as a black and white checker board
if ((x + z) % 2 == 0)
for(ColorDirection dir : ColorDirection.values())
// have each direction be the same
// color if debugging
colors[dir.value] = DEBUG_WHITE;
else
for(ColorDirection dir : ColorDirection.values())
colors[dir.value] = DEBUG_BLACK;
}
}
}
return colors;
}
/**
* Outputs all data in csv format
* Outputs all data in a csv format
* with the given delimiter.
* <br>
* Exports data in the form:
@@ -286,14 +373,9 @@ public class LodChunk
s += Integer.toString(x) + DATA_DELIMITER + Integer.toString(z) + DATA_DELIMITER;
s += Short.toString(height) + DATA_DELIMITER;
s += Short.toString(depth) + DATA_DELIMITER;
for(int i = 0; i < colors.length; i++)
{
s += Integer.toString(colors[i].getRed()) + DATA_DELIMITER + Integer.toString(colors[i].getGreen()) + DATA_DELIMITER + Integer.toString(colors[i].getBlue()) + DATA_DELIMITER;
}
for (LodDataPoint[] dataPointArray : dataPoints)
for(LodDataPoint dataPoint : dataPointArray)
s += dataPoint.toData();
return s;
}
@@ -306,7 +388,8 @@ public class LodChunk
s += "x: " + x + " z: " + z + "\t";
s += "(" + colors[ColorDirection.TOP.value].getRed() + ", " + colors[ColorDirection.TOP.value].getGreen() + ", " + colors[ColorDirection.TOP.value].getBlue() + ")";
// TODO
//s += "(" + colors[ColorDirection.TOP.value].getRed() + ", " + colors[ColorDirection.TOP.value].getGreen() + ", " + colors[ColorDirection.TOP.value].getBlue() + ")";
return s;
}
@@ -0,0 +1,82 @@
package com.seibel.lod.objects;
import java.awt.Color;
import com.seibel.lod.enums.ColorDirection;
import com.seibel.lod.handlers.LodDimensionFileHandler;
/**
* This stores the height and color
* for a specific area in a LodChunk.
*
* @author James Seibel
* @version 6-12-2021
*/
public class LodDataPoint
{
/** This is what separates each piece of data in the toData method */
private static final char DATA_DELIMITER = LodDimensionFileHandler.DATA_DELIMITER;
private static final Color INVISIBLE = new Color(0,0,0,0);
/** highest point */
public short height;
/** lowest point */
public short depth;
/** The average color for the 6 cardinal directions */
public Color colors[];
/**
* default constructor
*/
public LodDataPoint()
{
height = 0;
depth = 0;
colors = new Color[ColorDirection.values().length];
// by default have the colors invisible
for(ColorDirection dir : ColorDirection.values())
colors[dir.value] = INVISIBLE;
}
public LodDataPoint(short newHeight, short newDepth, Color[] newColors)
{
height = newHeight;
depth = newDepth;
colors = newColors;
}
/**
* Outputs all data in a csv format
* with the given delimiter.
* <br>
* Exports data in the form:
* <br>
* height, depth, rgb color data
*
* <br>
* example output:
* <br>
* 4, 0, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255,
*/
public String toData()
{
String s = Short.toString(height) + DATA_DELIMITER;
s += Short.toString(depth) + DATA_DELIMITER;
for(int i = 0; i < colors.length; i++)
{
s += Integer.toString(colors[i].getRed()) + DATA_DELIMITER + Integer.toString(colors[i].getGreen()) + DATA_DELIMITER + Integer.toString(colors[i].getBlue()) + DATA_DELIMITER;
}
return s;
}
}
@@ -7,7 +7,7 @@ package com.seibel.lod.objects;
* one file in the file system.
*
* @author James Seibel
* @version 1-22-2021
* @version 6-12-2021
*/
public class LodRegion
{
@@ -61,9 +61,6 @@ public class LodRegion
int arrayX = Math.abs(chunkX % SIZE);
int arrayZ = Math.abs(chunkZ % SIZE);
if(arrayX >= SIZE || arrayZ >= SIZE)
return null;
return chunks[arrayX][arrayZ];
}