Fixed LodQuadTree
Added QuadTreeImage to visualize how the quadTree is builded
This commit is contained in:
@@ -1,25 +1,20 @@
|
||||
package com.seibel.lod.builders;
|
||||
|
||||
import com.seibel.lod.enums.LodDetail;
|
||||
import com.seibel.lod.handlers.LodConfig;
|
||||
import com.seibel.lod.objects.LodChunk;
|
||||
import com.seibel.lod.objects.LodDataPoint;
|
||||
import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.objects.LodWorld;
|
||||
import com.seibel.lod.objects.quadTree.LodNodeData;
|
||||
import com.seibel.lod.objects.quadTree.LodQuadTreeDimension;
|
||||
import com.seibel.lod.objects.quadTree.LodQuadTreeWorld;
|
||||
import kaptainwutax.biomeutils.source.BiomeSource;
|
||||
import kaptainwutax.biomeutils.source.OverworldBiomeSource;
|
||||
import kaptainwutax.mcutils.state.Dimension;
|
||||
import kaptainwutax.mcutils.version.MCVersion;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.IWorld;
|
||||
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 java.awt.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@@ -28,24 +23,32 @@ public class LodNodeBuilder {
|
||||
private long seed;
|
||||
private DimensionType dimension;
|
||||
|
||||
/** Default size of any LOD regions we use */
|
||||
public static final int CHUNK_DATA_WIDTH = LodNodeData.CHUNK_WIDTH;
|
||||
public static final int CHUNK_SECTION_HEIGHT = 256;
|
||||
public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG;
|
||||
|
||||
/**
|
||||
* Default size of any LOD regions we use
|
||||
*/
|
||||
public int regionWidth = 5;
|
||||
|
||||
|
||||
/** fast biome calculator */
|
||||
private BiomeSource biomeSource;
|
||||
/**
|
||||
* fast biome calculator
|
||||
*/
|
||||
//private BiomeSource biomeSource;
|
||||
//Biome biome=biomeSource.getBiome(x,y,z); // here y is always 0 no matter what you pass
|
||||
|
||||
public LodNodeBuilder(){
|
||||
public LodNodeBuilder() {
|
||||
|
||||
}
|
||||
/*
|
||||
public setApproxGenerator(long seed){
|
||||
//Dimension.OVERWORLD;
|
||||
//Dimension.END;
|
||||
//Dimension.NETHER;
|
||||
biomeSource = BiomeSource.of(Dimension.OVERWORLD ,MCVersion.v1_16_4, seed);
|
||||
}
|
||||
|
||||
public void generateLodNodeAsync(List<LodNodeData> dataList){
|
||||
Thread thread = new Thread(() ->{
|
||||
for(LodNodeData data : dataList){
|
||||
@@ -57,9 +60,9 @@ public class LodNodeBuilder {
|
||||
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world)
|
||||
{
|
||||
public void generateLodNodeAsync(IChunk chunk, LodQuadTreeWorld lodWorld, IWorld world) {
|
||||
if (lodWorld == null || !lodWorld.getIsWorldLoaded())
|
||||
return;
|
||||
|
||||
@@ -71,28 +74,22 @@ public class LodNodeBuilder {
|
||||
|
||||
Thread thread = new Thread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
DimensionType dim = world.getDimensionType();
|
||||
try {
|
||||
DimensionType dim = world.dimensionType();
|
||||
|
||||
LodChunk lod = generateLodFromChunk(chunk, config);
|
||||
LodNodeData node = generateLodNodeFromChunk(chunk);
|
||||
|
||||
LodDimension lodDim;
|
||||
LodQuadTreeDimension lodDim;
|
||||
|
||||
if (lodWorld.getLodDimension(dim) == null)
|
||||
{
|
||||
lodDim = new LodDimension(dim, lodWorld, regionWidth);
|
||||
if (lodWorld.getLodDimension(dim) == null) {
|
||||
lodDim = new LodQuadTreeDimension(dim, lodWorld, regionWidth);
|
||||
lodWorld.addLodDimension(lodDim);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
lodDim = lodWorld.getLodDimension(dim);
|
||||
}
|
||||
|
||||
lodDim.addLod(lod);
|
||||
}
|
||||
catch(IllegalArgumentException | NullPointerException e)
|
||||
{
|
||||
lodDim.addNode(node);
|
||||
} catch (IllegalArgumentException | NullPointerException e) {
|
||||
// if the world changes while LODs are being generated
|
||||
// they will throw errors as they try to access things that no longer
|
||||
// exist.
|
||||
@@ -104,69 +101,295 @@ public class LodNodeBuilder {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a LodChunk for a chunk in the given world.
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* thrown if either the chunk or world is null.
|
||||
* @throws IllegalArgumentException thrown if either the chunk or world is null.
|
||||
*/
|
||||
public LodChunk generateLodFromChunk(IChunk chunk) throws IllegalArgumentException
|
||||
{
|
||||
return generateLodFromChunk(chunk, new LodBuilderConfig());
|
||||
public LodNodeData generateLodNodeFromChunk(IChunk chunk) throws IllegalArgumentException {
|
||||
return generateLodNodeFromChunk(chunk, new LodBuilderConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LodChunk for a chunk in the given world.
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* thrown if either the chunk or world is null.
|
||||
* @throws IllegalArgumentException thrown if either the chunk or world is null.
|
||||
* @return
|
||||
*/
|
||||
public LodChunk generateLodFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException
|
||||
{
|
||||
if(chunk == null)
|
||||
public LodNodeData generateLodNodeFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException {
|
||||
if (chunk == null)
|
||||
throw new IllegalArgumentException("generateLodFromChunk given a null chunk");
|
||||
|
||||
|
||||
LodDetail detail = LodConfig.CLIENT.lodDetail.get();
|
||||
LodDataPoint[][] dataPoints = new LodDataPoint[detail.lengthCount][detail.lengthCount];
|
||||
int startX = chunk.getPos().getMinBlockX();
|
||||
int startZ = chunk.getPos().getMinBlockZ();
|
||||
int endX = chunk.getPos().getMaxBlockX();
|
||||
int endZ = chunk.getPos().getMaxBlockZ();
|
||||
|
||||
for(int i = 0; i < detail.lengthCount * detail.lengthCount; i++)
|
||||
{
|
||||
int startX = detail.startX[i];
|
||||
int startZ = detail.startZ[i];
|
||||
int endX = detail.endX[i];
|
||||
int endZ = detail.endZ[i];
|
||||
Color color = generateLodColorForArea(chunk, config, startX, startZ, endX, endZ);
|
||||
|
||||
Color color;
|
||||
short height;
|
||||
short depth;
|
||||
|
||||
color = generateLodColorForArea(chunk, config, startX, startZ, endX, endZ);
|
||||
/**TODO I HAVE TO RE-ADD THE HEIGHTMAP**/
|
||||
height = determineHeightPointForArea(chunk.getSections(), startX, startZ, endX, endZ);
|
||||
depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ);
|
||||
|
||||
|
||||
short height;
|
||||
short depth;
|
||||
|
||||
if (!config.useHeightmap)
|
||||
{
|
||||
height = determineHeightPointForArea(chunk.getSections(), startX, startZ, endX, endZ);
|
||||
depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
height = determineHeightPoint(chunk.getHeightmap(LodChunk.DEFAULT_HEIGHTMAP), startX, startZ, endX, endZ);
|
||||
depth = 0;
|
||||
}
|
||||
|
||||
int x = i / detail.lengthCount;
|
||||
int z = i % detail.lengthCount;
|
||||
|
||||
dataPoints[x][z] = new LodDataPoint(height, depth, color);
|
||||
}
|
||||
|
||||
return new LodChunk(chunk.getPos(), dataPoints, detail);
|
||||
return new LodNodeData(LodNodeData.CHUNK_LEVEL, chunk.getPos().x, chunk.getPos().z, height, depth, color, true);
|
||||
}
|
||||
|
||||
|
||||
//=====================//
|
||||
// constructor helpers //
|
||||
//=====================//
|
||||
|
||||
|
||||
/**
|
||||
* Find the lowest valid point from the bottom.
|
||||
*
|
||||
* @param chunkSections
|
||||
* @param startX
|
||||
* @param startZ
|
||||
* @param endX
|
||||
* @param endZ
|
||||
*/
|
||||
private short determineBottomPointForArea(ChunkSection[] chunkSections,
|
||||
int startX, int startZ, int endX, int endZ) {
|
||||
int numberOfBlocksRequired = ((endX - startX) * (endZ - startZ) / 2);
|
||||
|
||||
// search from the bottom up
|
||||
for (int section = 0; section < CHUNK_DATA_WIDTH; section++) {
|
||||
for (int y = 0; y < CHUNK_SECTION_HEIGHT; y++) {
|
||||
int numberOfBlocksFound = 0;
|
||||
|
||||
for (int x = startX; x < endX; x++) {
|
||||
for (int z = startZ; z < endZ; z++) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we never found a valid LOD point
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param chunkSections
|
||||
* @param startX
|
||||
* @param startZ
|
||||
* @param endX
|
||||
* @param endZ
|
||||
*/
|
||||
private short determineHeightPointForArea(ChunkSection[] chunkSections,
|
||||
int startX, int startZ, int endX, int endZ) {
|
||||
int numberOfBlocksRequired = ((endX - startX) * (endZ - startZ) / 2);
|
||||
// search from the top down
|
||||
for (int section = chunkSections.length - 1; section >= 0; section--) {
|
||||
for (int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--) {
|
||||
int numberOfBlocksFound = 0;
|
||||
|
||||
for (int x = startX; x < endX; x++) {
|
||||
for (int z = startZ; z < endZ; z++) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we never found a valid LOD point
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the color for the given chunk using biome
|
||||
* water color, foliage color, and grass color.
|
||||
*
|
||||
* @param config_useSolidBlocksInColorGen <br>
|
||||
* If true we look down from the top of the <br>
|
||||
* chunk until we find a non-invisible block, and then use <br>
|
||||
* its color. If false we generate the color immediately for <br>
|
||||
* each x and z.
|
||||
* @param config_useBiomeColors <br>
|
||||
* If true use biome foliage, water, and grass colors, <br>
|
||||
* otherwise use the
|
||||
*/
|
||||
private Color generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) {
|
||||
ChunkSection[] chunkSections = chunk.getSections();
|
||||
|
||||
int numbOfBlocks = 0;
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
|
||||
|
||||
for (int x = startX; x < endX; x++) {
|
||||
for (int z = startZ; z < endZ; z++) {
|
||||
boolean foundBlock = false;
|
||||
|
||||
// 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;
|
||||
|
||||
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) {
|
||||
Biome biome = chunk.getBiomes().getNoiseBiome(x, y + i * chunkSections.length, z);
|
||||
|
||||
if (biome.getBiomeCategory() == Biome.Category.OCEAN ||
|
||||
biome.getBiomeCategory() == Biome.Category.RIVER) {
|
||||
colorInt = biome.getWaterColor();
|
||||
} else if (biome.getBiomeCategory() == Biome.Category.EXTREME_HILLS) {
|
||||
colorInt = Blocks.STONE.defaultMaterialColor().col;
|
||||
} else if (biome.getBiomeCategory() == Biome.Category.ICY) {
|
||||
colorInt = LodUtil.colorToInt(Color.WHITE);
|
||||
} else if (biome.getBiomeCategory() == Biome.Category.THEEND) {
|
||||
colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col;
|
||||
} else if (config.useSolidBlocksInColorGen) {
|
||||
colorInt = getColorForBlock(x, z, blockState, biome);
|
||||
} else {
|
||||
colorInt = biome.getGrassColor(x, z);
|
||||
}
|
||||
} else {
|
||||
Biome biome = chunk.getBiomes().getNoiseBiome(x, y + i * chunkSections.length, z);
|
||||
colorInt = getColorForBlock(x, z, blockState, biome);
|
||||
}
|
||||
|
||||
|
||||
Color c = LodUtil.intToColor(colorInt);
|
||||
|
||||
red += c.getRed();
|
||||
green += c.getGreen();
|
||||
blue += c.getBlue();
|
||||
|
||||
numbOfBlocks++;
|
||||
|
||||
|
||||
// we found a valid block, skip to the
|
||||
// next x and z
|
||||
foundBlock = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (numbOfBlocks == 0)
|
||||
numbOfBlocks = 1;
|
||||
|
||||
red /= numbOfBlocks;
|
||||
green /= numbOfBlocks;
|
||||
blue /= numbOfBlocks;
|
||||
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a color int for a given block.
|
||||
*/
|
||||
private int getColorForBlock(int x, int z, BlockState blockState, Biome biome) {
|
||||
int colorInt = 0;
|
||||
|
||||
if (blockState == Blocks.AIR.defaultBlockState()) {
|
||||
colorInt = biome.getGrassColor(x, z);
|
||||
} else if (blockState.getBlock() instanceof LeavesBlock) {
|
||||
Color leafColor = LodUtil.intToColor(biome.getFoliageColor()).darker();
|
||||
colorInt = LodUtil.colorToInt(leafColor);
|
||||
} else if (blockState.getBlock() instanceof GrassBlock) {
|
||||
colorInt = biome.getGrassColor(x, z);
|
||||
} else if (blockState.getBlock() instanceof FlowingFluidBlock) {
|
||||
colorInt = biome.getWaterColor();
|
||||
} else {
|
||||
colorInt = blockState.materialColor.col;
|
||||
}
|
||||
|
||||
return colorInt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (chunkSections[sectionIndex] == 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) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ public class LodNodeData {
|
||||
//if dirty is true, then this node have unsaved changes
|
||||
public boolean dirty;
|
||||
|
||||
|
||||
/**
|
||||
* Creates and empty LodDataPoint
|
||||
* This LodDataPoint only contains the position data
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.seibel.lod.objects.quadTree;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This object contains all data useful to render LodBlock in a region (32x32 chunk o 512x512 block)
|
||||
* for every node it contains the border of the block, the size, the position at it's level, the color, the height and the depth.
|
||||
@@ -36,7 +35,7 @@ public class LodQuadTree {
|
||||
//data useful to render
|
||||
//if children are present then lodNodeData should be a combination of the lodData of the child. This can be
|
||||
//turned off by deselecting the recursive update in all update method.
|
||||
private final LodNodeData lodNodeData;
|
||||
private LodNodeData lodNodeData;
|
||||
/*
|
||||
.____.____.
|
||||
| NW | NE | |
|
||||
@@ -137,8 +136,8 @@ public class LodQuadTree {
|
||||
int posX = newLodNodeData.posX;
|
||||
int posZ = newLodNodeData.posZ;
|
||||
short widthRatio = (short) (lodNodeData.width / newLodNodeData.width);
|
||||
int NS = (posX / widthRatio) % lodNodeData.posX;
|
||||
int WE = (posZ / widthRatio) % lodNodeData.posZ;
|
||||
int NS = (posX / widthRatio) % 2;
|
||||
int WE = (posZ / widthRatio) % 2;
|
||||
if (getChild(NS, WE) == null) {
|
||||
setChild(NS, WE);
|
||||
}
|
||||
@@ -147,10 +146,10 @@ public class LodQuadTree {
|
||||
return false;
|
||||
} else {
|
||||
if (targetLevel == currentLevel - 1) {
|
||||
child.setLodNodeData(lodNodeData, updateHigherLevel);
|
||||
child.setLodNodeData(newLodNodeData, true);
|
||||
return true;
|
||||
} else {
|
||||
return child.setNodeAtLowerLevel(lodNodeData, updateHigherLevel);
|
||||
return child.setNodeAtLowerLevel(newLodNodeData, updateHigherLevel);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -159,6 +158,32 @@ public class LodQuadTree {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param posX
|
||||
* @param posZ
|
||||
* @param level
|
||||
* @return
|
||||
*/
|
||||
public LodNodeData getNodeAtLevelPosition(int posX, int posZ, byte level) {
|
||||
byte targetLevel = level;
|
||||
byte currentLevel = lodNodeData.level;
|
||||
if (targetLevel == currentLevel) {
|
||||
return lodNodeData;
|
||||
} else if (targetLevel < currentLevel) {
|
||||
short widthRatio = (short) (lodNodeData.width / Math.pow(2, level));
|
||||
int NS = (posX / widthRatio) % lodNodeData.posX;
|
||||
int WE = (posZ / widthRatio) % lodNodeData.posZ;
|
||||
if (getChild(NS, WE) == null) {
|
||||
return lodNodeData;
|
||||
}
|
||||
LodQuadTree child = getChild(NS, WE);
|
||||
return child.getNodeAtLevelPosition(posX, posZ, level);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LodQuadTree getChild(int NS, int WE) {
|
||||
return children[NS][WE];
|
||||
}
|
||||
@@ -223,7 +248,7 @@ public class LodQuadTree {
|
||||
nodeFull = isFull;
|
||||
nodeEmpty = isEmpty;
|
||||
lodNodeData.combineData(dataList);
|
||||
if (lodNodeData.level > 0 && recursiveUpdate) {
|
||||
if (lodNodeData.level < 9 && recursiveUpdate) {
|
||||
this.parent.updateLevel(recursiveUpdate);
|
||||
}
|
||||
}
|
||||
@@ -262,20 +287,26 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
/**
|
||||
* method to get certain nodes from the LodQuadTree
|
||||
* @return list of nodes
|
||||
* This method will return all the nodes that can be rendered based on the data given
|
||||
*
|
||||
* @param x position of the player
|
||||
* @param z position of the player
|
||||
* @param targetLevel minimum level that can be rendered
|
||||
* @param maxDistance maximum distance from the player
|
||||
* @param minDistance minimum distance from the player
|
||||
* @return
|
||||
*/
|
||||
public List<LodNodeData> getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance){
|
||||
int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX,2) + Math.pow(z + lodNodeData.centerZ,2));
|
||||
public List<LodNodeData> getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) {
|
||||
int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX, 2) + Math.pow(z + lodNodeData.centerZ, 2));
|
||||
List<LodNodeData> nodeList = new ArrayList<>();
|
||||
if(distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) {
|
||||
if (distance > maxDistance || distance < minDistance || targetLevel < lodNodeData.level) {
|
||||
return nodeList;
|
||||
}
|
||||
if(targetLevel == lodNodeData.level || !isThereAnyChild()){
|
||||
if(!lodNodeData.voidNode){
|
||||
if (targetLevel == lodNodeData.level || !isThereAnyChild()) {
|
||||
if (!lodNodeData.voidNode) {
|
||||
nodeList.add(lodNodeData);
|
||||
return nodeList;
|
||||
}else{
|
||||
} else {
|
||||
return nodeList;
|
||||
}
|
||||
} else {
|
||||
@@ -283,7 +314,7 @@ public class LodQuadTree {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTree child = children[NS][WE];
|
||||
if (child != null) {
|
||||
nodeList.addAll(child.getNodeToRender(x,z,targetLevel,maxDistance,minDistance));
|
||||
nodeList.addAll(child.getNodeToRender(x, z, targetLevel, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,33 +323,40 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
/**
|
||||
* method to get certain nodes from the LodQuadTree
|
||||
* @return list of nodes
|
||||
* Nodes that can be generated in the approximated version
|
||||
* A level is generated only if it has child and is higher than the target level
|
||||
* @param x
|
||||
* @param z
|
||||
* @param targetLevel
|
||||
* @param maxDistance
|
||||
* @param minDistance
|
||||
* @return
|
||||
*/
|
||||
public List<AbstractMap.SimpleEntry<LodNodeData,Integer>> getNodeToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance){
|
||||
int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX,2) + Math.pow(z + lodNodeData.centerZ,2));
|
||||
List<AbstractMap.SimpleEntry<LodNodeData,Integer>> nodeList = new ArrayList<>();
|
||||
if(distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) {
|
||||
public List<AbstractMap.SimpleEntry<LodQuadTree, Integer>> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) {
|
||||
int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX, 2) + Math.pow(z + lodNodeData.centerZ, 2));
|
||||
List<AbstractMap.SimpleEntry<LodQuadTree, Integer>> nodeList = new ArrayList<>();
|
||||
if (distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level || lodNodeData.real) {
|
||||
return nodeList;
|
||||
}
|
||||
if(targetLevel == lodNodeData.level){
|
||||
return nodeList;
|
||||
} else {
|
||||
if(!isThereAnyChild()){
|
||||
if(isThereAnyChild()) {
|
||||
//THIS LEVEL HAS CHILD SO IT'S GENERATED.
|
||||
if (targetLevel != lodNodeData.level) {
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTree child = children[NS][WE];
|
||||
if (child != null) {
|
||||
nodeList.addAll(child.getNodeToGenerate(x,z,targetLevel,maxDistance,minDistance));
|
||||
if (children[NS][WE] == null) {
|
||||
setChild(NS,WE);
|
||||
}
|
||||
LodQuadTree child = children[NS][WE];
|
||||
nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, maxDistance, minDistance));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
nodeList.add( new AbstractMap.SimpleEntry<>(lodNodeData,distance));
|
||||
}
|
||||
} else {
|
||||
nodeList.add(new AbstractMap.SimpleEntry<>(this, distance));
|
||||
}
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* simple getter for lodNodeData
|
||||
*
|
||||
@@ -335,7 +373,11 @@ public class LodQuadTree {
|
||||
* @param updateHigherLevel if true it will update all the upper levels.
|
||||
*/
|
||||
public void setLodNodeData(LodNodeData newLodNodeData, boolean updateHigherLevel) {
|
||||
this.lodNodeData.update(lodNodeData);
|
||||
if (this.lodNodeData == null) {
|
||||
this.lodNodeData = newLodNodeData;
|
||||
} else {
|
||||
this.lodNodeData.update(newLodNodeData);
|
||||
}
|
||||
//a recursive update is necessary to change higher level
|
||||
if (parent != null && updateHigherLevel) parent.updateLevel(true);
|
||||
}
|
||||
@@ -345,7 +387,7 @@ public class LodQuadTree {
|
||||
}
|
||||
|
||||
public boolean isThereAnyChild() {
|
||||
return nodeEmpty;
|
||||
return !nodeEmpty;
|
||||
}
|
||||
|
||||
public boolean isNodeReal() {
|
||||
@@ -355,9 +397,19 @@ public class LodQuadTree {
|
||||
public boolean isRenderable() {
|
||||
return (lodNodeData != null);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
EXAMPLES OF USES
|
||||
|
||||
*/
|
||||
public String toString(){
|
||||
String s = lodNodeData.toString();
|
||||
if(isThereAnyChild()){
|
||||
for (int NS = 0; NS <= 1; NS++) {
|
||||
for (int WE = 0; WE <= 1; WE++) {
|
||||
LodQuadTree child = children[NS][WE];
|
||||
if (child != null) {
|
||||
s += '\n' + child.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class LodQuadTreeDimension {
|
||||
private LodQuadTreeDimensionFileHandler fileHandler;
|
||||
|
||||
|
||||
public LodQuadTreeDimension(DimensionType newDimension, LodWorld lodWorld, int newMaxWidth)
|
||||
public LodQuadTreeDimension(DimensionType newDimension, LodQuadTreeWorld lodWorld, int newMaxWidth)
|
||||
{
|
||||
dimension = newDimension;
|
||||
width = newMaxWidth;
|
||||
@@ -39,7 +39,7 @@ public class LodQuadTreeDimension {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
File saveDir;
|
||||
if(mc.isIntegratedServerRunning())
|
||||
if(mc.hasSingleplayerServer())
|
||||
{
|
||||
// local world
|
||||
|
||||
@@ -47,15 +47,15 @@ public class LodQuadTreeDimension {
|
||||
seed = serverWorld.getSeed();
|
||||
// provider needs a separate variable to prevent
|
||||
// the compiler from complaining
|
||||
ServerChunkProvider provider = serverWorld.getChunkProvider();
|
||||
saveDir = new File(provider.getSavedData().folder.getCanonicalFile().getPath() + File.separatorChar + "lod");
|
||||
ServerChunkProvider provider = serverWorld.getChunkSource();
|
||||
saveDir = new File(provider.dataStorage.dataFolder.getCanonicalFile().getPath() + File.separatorChar + "lod");
|
||||
}
|
||||
else
|
||||
{
|
||||
// connected to server
|
||||
|
||||
saveDir = new File(mc.gameDir.getCanonicalFile().getPath() +
|
||||
File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.world));
|
||||
saveDir = new File(mc.gameDirectory.getCanonicalFile().getPath() +
|
||||
File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.level));
|
||||
}
|
||||
|
||||
fileHandler = new LodQuadTreeDimensionFileHandler(saveDir, this);
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
package com.seibel.lod.objects.quadTree;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
@SuppressWarnings("serial")
|
||||
public class QuadTreeImage extends JPanel {
|
||||
private static final int PREF_W = 600;
|
||||
private static final int PREF_H = PREF_W;
|
||||
private List<MyDrawable> drawables = new ArrayList<>();
|
||||
|
||||
public QuadTreeImage() {
|
||||
setBackground(Color.white);
|
||||
}
|
||||
|
||||
public void addMyDrawable(MyDrawable myDrawable) {
|
||||
drawables.add(myDrawable);
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
// make it bigger
|
||||
public Dimension getPreferredSize() {
|
||||
if (isPreferredSizeSet()) {
|
||||
return super.getPreferredSize();
|
||||
}
|
||||
return new Dimension(PREF_W, PREF_H);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
for (MyDrawable myDrawable : drawables) {
|
||||
myDrawable.draw(g2);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
drawables.clear();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private static void createAndShowGui( ) {
|
||||
LodQuadTree lodQuadTree = new LodQuadTree(0,0);
|
||||
for(int i = 0; i<9; i++){
|
||||
List<AbstractMap.SimpleEntry<LodQuadTree, Integer>> levelToGenerate= lodQuadTree.getLevelToGenerate(0,0,(byte) (9-i),1000,0);
|
||||
boolean bw= true;
|
||||
System.out.println(levelToGenerate);
|
||||
for(AbstractMap.SimpleEntry<LodQuadTree, Integer> levelDist : levelToGenerate){
|
||||
LodQuadTree level = levelDist.getKey();
|
||||
Color color ;
|
||||
if(bw){
|
||||
color = Color.red;
|
||||
bw = false;
|
||||
}else{
|
||||
color = Color.blue;
|
||||
bw = true;
|
||||
}
|
||||
|
||||
int posZ = level.getLodNodeData().startX/LodNodeData.BLOCK_WIDTH;
|
||||
int posX = level.getLodNodeData().startZ/LodNodeData.BLOCK_WIDTH;
|
||||
System.out.println(posX + " " + posZ);
|
||||
lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true);
|
||||
|
||||
posZ = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH;
|
||||
posX = level.getLodNodeData().startZ/LodNodeData.BLOCK_WIDTH;
|
||||
System.out.println(posX + " " + posZ);
|
||||
lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true);
|
||||
|
||||
posZ = level.getLodNodeData().startX/LodNodeData.BLOCK_WIDTH;
|
||||
posX = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH;
|
||||
System.out.println(posX + " " + posZ);
|
||||
lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true);
|
||||
|
||||
posZ = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH;
|
||||
posX = level.getLodNodeData().endZ/LodNodeData.BLOCK_WIDTH;
|
||||
System.out.println(posX + " " + posZ);
|
||||
lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true);
|
||||
}
|
||||
}
|
||||
System.out.println(lodQuadTree.getNodeList(false,false,false));
|
||||
|
||||
Collection<LodNodeData> lodList = lodQuadTree.getNodeList(false,false,false);
|
||||
|
||||
final List<MyDrawable> myDrawables = new ArrayList<>();
|
||||
for(LodNodeData data : lodList) {
|
||||
myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX+100, data.startZ+100, data.width, data.width),
|
||||
data.color, new BasicStroke(1)));
|
||||
}
|
||||
|
||||
final QuadTreeImage quadTreeImage = new QuadTreeImage();
|
||||
|
||||
JFrame frame = new JFrame("DrawChit");
|
||||
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
frame.getContentPane().add(quadTreeImage);
|
||||
frame.pack();
|
||||
frame.setLocationByPlatform(true);
|
||||
frame.setVisible(true);
|
||||
|
||||
int timerDelay = 1;
|
||||
new Timer(timerDelay, new ActionListener() {
|
||||
private int drawCount = 0;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (drawCount >= myDrawables.size()) {
|
||||
drawCount = 0;
|
||||
quadTreeImage.clearAll();
|
||||
} else {
|
||||
quadTreeImage.addMyDrawable(myDrawables.get(drawCount));
|
||||
drawCount++;
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
createAndShowGui();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class MyDrawable {
|
||||
private Shape shape;
|
||||
private Color color;
|
||||
private Stroke stroke;
|
||||
|
||||
public MyDrawable(Shape shape, Color color, Stroke stroke) {
|
||||
this.shape = shape;
|
||||
this.color = color;
|
||||
this.stroke = stroke;
|
||||
}
|
||||
|
||||
public Shape getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Stroke getStroke() {
|
||||
return stroke;
|
||||
}
|
||||
|
||||
public void draw(Graphics2D g2) {
|
||||
Color oldColor = g2.getColor();
|
||||
Stroke oldStroke = g2.getStroke();
|
||||
|
||||
g2.setColor(color);
|
||||
g2.setStroke(stroke);
|
||||
g2.draw(shape);
|
||||
|
||||
g2.setColor(oldColor);
|
||||
g2.setStroke(oldStroke);
|
||||
}
|
||||
|
||||
public void fill(Graphics2D g2) {
|
||||
Color oldColor = g2.getColor();
|
||||
Stroke oldStroke = g2.getStroke();
|
||||
|
||||
g2.setColor(color);
|
||||
g2.setStroke(stroke);
|
||||
g2.fill(shape);
|
||||
|
||||
g2.setColor(oldColor);
|
||||
g2.setStroke(oldStroke);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.seibel.lod.objects.quadTree;
|
||||
|
||||
import com.seibel.lod.builders.LodBuilder;
|
||||
import com.seibel.lod.builders.LodNodeBuilder;
|
||||
import com.seibel.lod.objects.LodDimension;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -23,36 +22,37 @@ public class UsesExamples {
|
||||
* Complete the new renderer
|
||||
* add everything to ClientProxy for the first test
|
||||
* */
|
||||
|
||||
/*
|
||||
LodQuadTreeWorld lodWorld = new LodQuadTreeWorld();
|
||||
LodQuadTreeDimension newLodDimension = new LodQuadTreeDimension(Minecraft.getInstance().world.getDimensionType(), Minecraft.getInstance().world, 10);
|
||||
lodWorld.addLodDimension(newLodDimension);
|
||||
|
||||
LodQuadTreeDimension lodDimension = lodWorld.getLodDimension(Minecraft.getInstance().world.getDimensionType());
|
||||
lodDimension.move(0,0);
|
||||
/*
|
||||
I will now generate some fake LodNodeData. This in the final implementation will be generated by a builder
|
||||
this lodNodeData will be put at level 6 of the QuadTree. This LodNodeData represent a block of width
|
||||
*/
|
||||
|
||||
//I will now generate some fake LodNodeData. This in the final implementation will be generated by a builder
|
||||
//this lodNodeData will be put at level 6 of the QuadTree. This LodNodeData represent a block of width
|
||||
|
||||
LodNodeData lodNodeData1 = new LodNodeData((byte) 6, 4, 4, 64, 0, new Color(0,200,0),true);
|
||||
LodNodeData lodNodeData2 = new LodNodeData((byte) 6, 4, 5, 64, 0, new Color(0,200,0),true);
|
||||
LodNodeData lodNodeData3 = new LodNodeData((byte) 6, 5, 4, 64, 0, new Color(0,0,200),true);
|
||||
/*
|
||||
add like this
|
||||
*/
|
||||
|
||||
//add like this
|
||||
|
||||
lodDimension.addNode(lodNodeData1);
|
||||
lodDimension.addNode(lodNodeData2);
|
||||
lodDimension.addNode(lodNodeData3);
|
||||
/*
|
||||
Automatic generation
|
||||
|
||||
*/
|
||||
//Automatic generation
|
||||
|
||||
List nodeToGenerate = (List) lodDimension.getRegion(0,0).getNodeToGenerate(0,0, (byte) 3,1000,0);
|
||||
Collections.sort(nodeToGenerate, Map.Entry.<LodNodeData, Integer>comparingByValue();
|
||||
Collections.sort(nodeToGenerate, Map.Entry.<LodNodeData, Integer>comparingByValue());
|
||||
|
||||
|
||||
// Call the builder to generate all the useful node
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Call the builder to generate all the useful node
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user