Re-Introduced HEIGHMAP mode correctly.

Added single get and add to the LevelContainer to avoid using temp arrays
This commit is contained in:
Leonardo
2021-09-15 13:23:41 +02:00
parent 6dc94b0cc2
commit cdeba2616c
13 changed files with 426 additions and 222 deletions
+5 -6
View File
@@ -11,14 +11,13 @@ public class Main
{
public static void main(String[] args)
{
/*
try
{
long[][] dataToMerge = new long[][]{
{DataPointUtil.createDataPoint(10, 5, 0, 0, 0)},
{DataPointUtil.createDataPoint(15, 5, 0, 0, 0)},
{DataPointUtil.createDataPoint(40, 20, 0, 0, 0)},
{DataPointUtil.createDataPoint(1, 0, 0, 0, 0)}};
{DataPointUtil.createDataPoint(10, 5, 0, 0, 0, 0)},
{DataPointUtil.createDataPoint(15, 5, 0, 0, 0, 0)},
{DataPointUtil.createDataPoint(40, 20, 0, 0, 0, 0)},
{DataPointUtil.createDataPoint(1, 0, 0, 0, 0, 0)}};
long[] data = DataPointUtil.mergeVerticalData(dataToMerge);
for (long dataPoint : data)
{
@@ -27,6 +26,6 @@ public class Main
}
}catch (Exception e){
e.printStackTrace();
}*/
}
}
}
@@ -26,6 +26,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.util.*;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
@@ -40,10 +42,6 @@ import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.proxy.GlProxy;
import com.seibel.lod.proxy.GlProxy.GlProxyContext;
import com.seibel.lod.render.LodRenderer;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.LightTexture;
@@ -67,72 +65,70 @@ public class LodBufferBuilder
* This holds the threads used to generate buffers.
*/
public static ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new LodThreadFactory(LodBufferBuilder.class.getSimpleName() + " - builder"));
/**
* The buffers that are used to create LODs using far fog
*/
public volatile BufferBuilder[][] buildableBuffers;
/**
* Used when building new VBOs
*/
public volatile VertexBuffer[][] buildableVbos;
/**
* VBOs that are sent over to the LodNodeRenderer
*/
public volatile VertexBuffer[][] drawableVbos;
/**
* if this is true the LOD buffers are currently being
* regenerated.
*/
public boolean generatingBuffers = false;
/**
* if this is true new LOD buffers have been generated
* and are waiting to be swapped with the drawable buffers
*/
private boolean switchVbos = false;
/**
* Size of the buffer builders in bytes last time we created them
*/
public int previousBufferSize = 0;
/**
* Width of the dimension in regions last time we created the buffers
*/
public int previousRegionWidth = 0;
/**
* this is used to prevent multiple threads creating, destroying, or using the buffers at the same time
*/
private ReentrantLock bufferLock = new ReentrantLock();
private static final int NUMBER_OF_DIRECTION = 4;
//in order -x, +x, -z, +z
private static final int[][] ADJ_DIRECTION = new int[][] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
private static final int[][] ADJ_DIRECTION = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private volatile Box[][] boxCache;
private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center;
/**
* This is the ChunkPos the player was at the last time the buffers were built.
* IE the center of the buffers last time they were built
*/
private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0, 0);
private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0, 0);
public LodBufferBuilder()
{
}
/**
* Create a thread to asynchronously generate LOD buffers
* centered around the given camera X and Z.
@@ -143,10 +139,10 @@ public class LodBufferBuilder
* swapped with the drawable buffers in the LodRenderer to be drawn.
*/
public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim,
BlockPos playerBlockPos, boolean fullRegen)
BlockPos playerBlockPos, boolean fullRegen)
{
/*
for(int i = 0; i<16; i++)
{
for(int j = 0; j<16; j++)
@@ -156,61 +152,61 @@ public class LodBufferBuilder
System.out.print(Integer.toHexString(lightTint) + " ");
}
System.out.println();
}
}*/
// only allow one generation process to happen at a time
if (generatingBuffers)
return;
if (buildableBuffers == null)
// setupBuffers hasn't been called yet
return;
generatingBuffers = true;
// round the player's block position down to the nearest chunk BlockPos
ChunkPos playerChunkPos = new ChunkPos(playerBlockPos);
BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition();
Thread thread = new Thread(() ->
{
bufferLock.lock();
try
{
long treeStart = System.currentTimeMillis();
long treeEnd = System.currentTimeMillis();
long startTime = System.currentTimeMillis();
ArrayList<Callable<Boolean>> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length);
startBuffers(fullRegen, lodDim);
// =====================//
// RENDERING PART //
// =====================//
RegionPos playerRegionPos = new RegionPos(playerChunkPos);
if (center == null)
center = playerRegionPos;
if (setsToRender == null)
setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length];
if (setsToRender.length != lodDim.regions.length)
setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length];
if (boxCache == null)
boxCache = new Box[lodDim.regions.length][lodDim.regions.length];
if (boxCache.length != lodDim.regions.length)
boxCache = new Box[lodDim.regions.length][lodDim.regions.length];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++)
{
for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++)
@@ -220,7 +216,7 @@ public class LodBufferBuilder
RegionPos regionPos = new RegionPos(
xRegion + lodDim.getCenterX() - Math.floorDiv(lodDim.getWidth(), 2),
zRegion + lodDim.getCenterZ() - Math.floorDiv(lodDim.getWidth(), 2));
// local position in the vbo and bufferBuilder arrays
BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion];
LodRegion region = lodDim.getRegion(regionPos.x, regionPos.z);
@@ -235,26 +231,26 @@ public class LodBufferBuilder
final int zR = zRegion;
Callable<Boolean> dataToRenderThread = () ->
{
//previous setToRender chache
if (setsToRender[xR][zR] == null)
{
setsToRender[xR][zR] = new PosToRenderContainer(minDetail, regionPos.x, regionPos.z);
}
if (boxCache[xR][zR] == null)
{
boxCache[xR][zR] = new Box();
}
PosToRenderContainer posToRender = setsToRender[xR][zR];
posToRender.clear(minDetail, regionPos.x, regionPos.z);
lodDim.getDataToRender(
posToRender,
regionPos,
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
byte detailLevel;
int posX;
int posZ;
@@ -275,62 +271,77 @@ public class LodBufferBuilder
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist)
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
{
continue;
}
// skip any chunks that Minecraft is going to render
try
{
//dataPoint = lodDim.getData(detailLevel, posX, posZ)[0];
for(long dataPoint : lodDim.getData(detailLevel, posX, posZ))
{
if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint))
if (region.getLodQualityMode() == LodQualityMode.HEIGHTMAP)
{
/*
for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++)
//dataPoint = lodDim.getData(detailLevel, posX, posZ)[0];
long dataPoint = lodDim.getSingleData(detailLevel, posX, posZ);
if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint))
{
xAdj = posX + ADJ_DIRECTION[direction][0];
zAdj = posZ + ADJ_DIRECTION[direction][1];
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
dataPoint = lodDim.getSingleData(detailLevel, posX, posZ);
if(DataPointUtil.getHeight(dataPoint) == LodBuilder.DEFAULT_HEIGHT && DataPointUtil.getDepth(dataPoint) == LodBuilder.DEFAULT_DEPTH)
continue;
for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++)
{
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& posToRender.contains(detailLevel, xAdj, zAdj))
xAdj = posX + ADJ_DIRECTION[direction][0];
zAdj = posZ + ADJ_DIRECTION[direction][1];
chunkXdist = LevelPosUtil.getChunkPos(detailLevel,xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel,zAdj) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
{
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj)[0];
} else
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction] = 0;
}
adjData[direction]= lodDim.getSingleData(detailLevel, xAdj, zAdj);
}else{
adjData[direction]= 0;
}
} else
{
if (posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj)[0];
} else
if (posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction] = 0;
adjData[direction] = lodDim.getSingleData(detailLevel, xAdj, zAdj);
}else{
adjData[direction]= 0;
}
}
}
}*/
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode);
}
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR],renderer.previousDebugMode);
}
} else if (region.getLodQualityMode() == LodQualityMode.MULTI_LOD)
{
//dataPoint = lodDim.getData(detailLevel, posX, posZ)[0];
for (long dataPoint : lodDim.getData(detailLevel, posX, posZ))
{
if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint))
{
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode);
}
}
}
} catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
return false;
}
} // for pos to in list to render
// the thread executed successfully
// the thread executed successfully
return true;
};
nodeToRenderThreads.add(dataToRenderThread);
@@ -351,7 +362,7 @@ public class LodBufferBuilder
}
}
long renderEnd = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
@SuppressWarnings("unused")
long buildTime = endTime - startTime;
@@ -366,38 +377,36 @@ public class LodBufferBuilder
// mark that the buildable buffers as ready to swap
switchVbos = true;
}
catch (Exception e)
} catch (Exception e)
{
ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: ");
e.printStackTrace();
}
finally
} finally
{
// regardless of if we successfully created the buffers
// we are done generating.
generatingBuffers = false;
// clean up any potentially open resources
if (buildableBuffers != null)
closeBuffers(fullRegen, lodDim);
// upload the new buffers
uploadBuffers(fullRegen, lodDim);
bufferLock.unlock();
}
});
mainGenThread.execute(thread);
return;
}
//===============================//
// BufferBuilder related methods //
//===============================//
/**
* Called from the LodRenderer to create the
* BufferBuilders. <br><br>
@@ -407,30 +416,30 @@ public class LodBufferBuilder
public void setupBuffers(int numbRegionsWide, int bufferMaxCapacity)
{
bufferLock.lock();
previousRegionWidth = numbRegionsWide;
previousBufferSize = bufferMaxCapacity;
buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide];
buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
for (int x = 0; x < numbRegionsWide; x++)
{
for (int z = 0; z < numbRegionsWide; z++)
{
buildableBuffers[x][z] = new BufferBuilder(bufferMaxCapacity);
buildableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
drawableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
}
}
bufferLock.unlock();
}
/**
* sets the buffers and Vbos to null, forcing them to be recreated. <br><br>
* <p>
@@ -439,14 +448,14 @@ public class LodBufferBuilder
public void destroyBuffers()
{
bufferLock.lock();
buildableBuffers = null;
buildableVbos = null;
drawableVbos = null;
bufferLock.unlock();
}
/**
* Calls begin on each of the buildable BufferBuilders.
*/
@@ -463,7 +472,7 @@ public class LodBufferBuilder
}
}
}
/**
* Calls end on each of the buildable BufferBuilders.
*/
@@ -472,9 +481,9 @@ public class LodBufferBuilder
for (int x = 0; x < buildableBuffers.length; x++)
for (int z = 0; z < buildableBuffers.length; z++)
if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.regen[x][z]))
buildableBuffers[x][z].end();
buildableBuffers[x][z].end();
}
/**
* Upload all buildableBuffers to the GPU.
*/
@@ -486,8 +495,8 @@ public class LodBufferBuilder
glProxy.setGlContext(GlProxyContext.LOD_BUILDER);
// only print console debugging for vboUpload once per upload cycle
boolean bufferMapFail = false;
for (int x = 0; x < buildableVbos.length; x++)
{
for (int z = 0; z < buildableVbos.length; z++)
@@ -500,14 +509,14 @@ public class LodBufferBuilder
}
}
}
// make sure all the buffers have been uploaded.
// this probably is necessary, but it makes me feel good :)
GL11.glFlush();
glProxy.setGlContext(GlProxyContext.NONE);
}
/**
* Uploads the uploadBuffer into the VBO in GPU memory.
*/
@@ -517,47 +526,46 @@ public class LodBufferBuilder
if (vbo.id != -1)
{
vbo.vertexCount = uploadBuffer.remaining() / vbo.format.getVertexSize();
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id);
// make sure enough space is allocated to fit the builderBuffer
GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer.capacity(), GL15C.GL_DYNAMIC_DRAW);
// try to get a pointer to the VBO's byteBuffer in GPU memory
ByteBuffer vboBuffer = GL15C.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
// upload the builderBuffer to the GPU
if (vboBuffer != null)
{
// This is the best way to upload lots of data, since writes directly to GPU
// memory, and doesn't pause OpenGL.
vboBuffer.put(uploadBuffer);
}
else
} else
{
// Sometimes the vboBuffer is null (I think it may be due to buffer sizes
// changing or a setup process that didn't complete), so in that case
// we have to use this method which is slower and pauses OpenGL,
// but always succeeds.
GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer, GL15C.GL_DYNAMIC_DRAW);
// only print to console once per upload cycle
if (!bufferMapFail)
ClientProxy.LOGGER.debug("LOD buffer upload: glMapBuffer failed, used slower glBufferData.");
bufferMapFail = true;
}
GL15C.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
// just used to improve debug printing
return bufferMapFail;
}
/**
* Get the newly created VBOs
*/
@@ -570,17 +578,17 @@ public class LodBufferBuilder
VertexBuffer[][] tmpVbo = drawableVbos;
drawableVbos = buildableVbos;
buildableVbos = tmpVbo;
drawableCenterChunkPos = buildableCenterChunkPos;
// the vbos have been swapped
switchVbos = false;
bufferLock.unlock();
}
return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos);
}
/**
* A simple container to pass multiple objects back in the getVertexBuffers method.
*/
@@ -588,14 +596,14 @@ public class LodBufferBuilder
{
public VertexBuffer[][] vbos;
public ChunkPos drawableCenterChunkPos;
public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos)
{
vbos = newVbos;
drawableCenterChunkPos = newDrawableCenterChunkPos;
}
}
/**
* If this is true the buildable near and far
* buffers have been generated and are ready to be
@@ -605,5 +613,5 @@ public class LodBufferBuilder
{
return switchVbos;
}
}
@@ -190,32 +190,39 @@ public class LodBuilder
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 = null
;
long singleData = 0;
long[] data = null;
boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER;
switch (lodQualityMode){
default:
case HEIGHTMAP:
data = ThreadMapUtil.getSingleAddDataArray();
long[] dataToMergeSingle;
dataToMergeSingle = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data[0] = DataPointUtil.mergeSingleData(dataToMergeSingle);
singleData = DataPointUtil.mergeSingleData(dataToMergeSingle);
lodDim.addSingleData(detailLevel,
posX,
posZ,
singleData,
false,
isServer);
break;
case MULTI_LOD:
long[][] dataToMergeVertical;
dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data = DataPointUtil.mergeVerticalData(dataToMergeVertical);
if (data.length == 0 || data == null)
data = new long[]{DataPointUtil.EMPTY_DATA};
lodDim.addData(detailLevel,
posX,
posZ,
data,
false,
isServer);
break;
}
if (data.length == 0 || data == null)
data = new long[]{DataPointUtil.EMPTY_DATA};
boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER;
lodDim.addData(detailLevel,
posX,
posZ,
data,
false,
isServer);
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
@@ -382,6 +389,9 @@ public class LodBuilder
int xAbs;
int yAbs;
int zAbs;
int lightBlock;
int lightSky;
BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0);
int index = 0;
@@ -414,8 +424,9 @@ public class LodBuilder
blockPos.set(xAbs, yAbs + 1, zAbs);
light = getLightValue(chunk, blockPos);
dataToMerge[index] = DataPointUtil.createDataPoint(height, depth, color, (light >> 4) & 0b1111, light & 0b1111, generation);
lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111;
dataToMerge[index] = DataPointUtil.createDataPoint(height, depth, color, lightSky, lightBlock, generation);
}
return dataToMerge;
}
@@ -440,6 +451,7 @@ public class LodBuilder
{
for (int yRel = 0; yRel < CHUNK_DATA_WIDTH; yRel++)
{
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
if (isLayerValidLodPoint(chunk, blockPos))
{
depth = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel);
@@ -474,6 +486,7 @@ public class LodBuilder
{
for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--)
{
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
if (isLayerValidLodPoint(chunk, blockPos))
{
height = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1);
@@ -537,6 +550,7 @@ public class LodBuilder
light += MinecraftWrapper.INSTANCE.getPlayer().level.getBrightness(LightType.SKY, blockPos) << 4;
//BlockState blockState = chunk.getBlockState(blockPos);
//lightBlock = (byte) blockState.getLightBlock(chunk, blockPos);
//lightBlock = (byte) blockState.getLightBlock(chunk, blockPos);
return light;
}
@@ -689,7 +703,7 @@ public class LodBuilder
BlockState blockState = chunk.getBlockState(blockPos);
if (blockState != null)
{
if (!blockState.getFluidState().isEmpty())
/*if (!blockState.getFluidState().isEmpty())
{
return true;
}
@@ -707,7 +721,7 @@ public class LodBuilder
} else
{
return false;
}
}*/
if (blockState.getBlock() != Blocks.AIR
&& blockState.getBlock() != Blocks.CAVE_AIR
&& blockState.getBlock() != Blocks.BARRIER)
@@ -718,4 +732,26 @@ public class LodBuilder
return false;
}
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
&& chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.CAVE_AIR
&& chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.BARRIER)
{
return true;
}
}
return false;
}
}
@@ -61,13 +61,14 @@ public class CubicLodTemplate extends AbstractLodTemplate
0,
posZ * width,
bufferCenterBlockPos);
int color;
int color;/*
boolean hasSkyLight = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasSkyLight();
boolean hasRoof = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasSkyLight();
int time = (int) (MinecraftWrapper.INSTANCE.getPlayer().level.getDayTime() - 13000);
boolean isDay = time < 0;
boolean isDay = time < 0;*/
//USE THIS IN THE boolean hasCeiling = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasCeiling();
color = DataPointUtil.getLightColor(data, (hasRoof & hasSkyLight), isDay);
//color = DataPointUtil.getLightColor(data, (hasRoof & hasSkyLight), isDay);
color = DataPointUtil.getColor(data);
if (debugging != DebugMode.OFF)
@@ -217,7 +218,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
} else
}else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
@@ -262,7 +263,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
} else
}
else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
@@ -307,7 +309,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
} else
}
else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
@@ -352,7 +355,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
} else
}
else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
@@ -376,6 +380,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
}
}
}
@Override
@@ -201,7 +201,7 @@ public class LodConfig
+ " Use 3d lods or 2d lods? \n"
+ " " + LodQualityMode.HEIGHTMAP.toString() + ": enable 2d lods with heightmap \n"
+ " " + LodQualityMode.MULTI_LOD.toString() + ": enable 3d lods with heightmap \n")
.defineEnum("lodGenerationQuality", LodQualityMode.HEIGHTMAP);
.defineEnum("lodQualityMode", LodQualityMode.HEIGHTMAP);
maxGenerationDetail = builder
.comment("\n\n"
@@ -193,8 +193,16 @@ public class LodDimensionFileHandler
data = bufferedReader.readLine();
bufferedReader.close();
switch (region.getLodQualityMode()){
default:
case HEIGHTMAP:
region.addLevel(new SingleLevelContainer(data));
break;
case MULTI_LOD:
region.addLevel(new VerticalLevelContainer(data));
break;
}
//region.addLevel(new SingleLevelContainer(data));
region.addLevel(new VerticalLevelContainer(data));
} catch (Exception e)
{
// the buffered reader encountered a
@@ -19,6 +19,15 @@ public interface LevelContainer
*/
public boolean addData(long[] data, int posX, int posZ);
/**With this you can add data to the level container
*
* @param data actual data to add in a array of long format.
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
public boolean addSingleData(long data, int posX, int posZ);
/**With this you can get data from the level container
*
* @param posX x position in the detail level
@@ -27,6 +36,14 @@ public interface LevelContainer
*/
public long[] getData(int posX, int posZ);
/**With this you can get data from the level container
*
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return the data in long array format
*/
public long getSingleData(int posX, int posZ);
/**
* @param posX x position in the detail level
* @param posZ z position in the detail level
@@ -467,6 +467,44 @@ public class LodDimension
return nodeAdded;
}
/**
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
* coordinates it will be overwritten.
*/
public Boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
boolean nodeAdded = region.addSingleData(detailLevel, posX, posZ, dataPoint, serverQuality);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
{
try
{
// mark the region as dirty so it will be saved to disk
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
regen[xIndex][zIndex] = true;
regenDimension = true;
} catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
// This method was probably called when the dimension was changing size.
// Hopefully this shouldn't be an issue.
}
}
return nodeAdded;
}
public void setToRegen(int xRegion, int zRegion)
{
int xIndex = (xRegion - center.x) + halfWidth;
@@ -535,6 +573,27 @@ public class LodDimension
return region.getData(detailLevel, posX, posZ);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
* <br>
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public long getSingleData(byte detailLevel, int posX, int posZ)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return DataPointUtil.EMPTY_DATA;
}
return region.getSingleData(detailLevel, posX, posZ);
}
/**
* Get the data point at the given X and Z coordinates
@@ -59,6 +59,7 @@ public class LodRegion
for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++)
{
switch (lodQualityMode){
default:
case HEIGHTMAP:
dataContainer[lod] = new SingleLevelContainer(lod);
break;
@@ -102,6 +103,31 @@ public class LodRegion
}
}
/**
* This method can be used to insert data into the LodRegion
*
* @param dataPoint
* @return
*/
public boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean serverQuality)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (!doesDataExist(detailLevel, posX, posZ) || serverQuality)
{
//update the number of node present
//if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++;
//add the node data
this.dataContainer[detailLevel].addSingleData(dataPoint, posX, posZ);
return true;
} else
{
return false;
}
}
/**
* This method will return the data in the position relative to the level of detail
*
@@ -114,6 +140,19 @@ public class LodRegion
return dataContainer[detailLevel].getData(posX, posZ);
}
/**
* This method will return the data in the position relative to the level of detail
*
* @return the data at the relative pos and level
*/
public long getSingleData(byte detailLevel, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getSingleData(posX, posZ);
}
/**
* This method will return all the levelPos that are renderable according to the requisite given in input
*
@@ -26,7 +26,7 @@ public class SingleLevelContainer implements LevelContainer
return true;
}
private boolean addSingleData(long newData, int posX, int posZ){
public boolean addSingleData(long newData, int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
data[posX][posZ] = newData;
@@ -42,7 +42,7 @@ public class SingleLevelContainer implements LevelContainer
return dataArray;
}
private long getSingleData(int posX, int posZ){
public long getSingleData(int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//Improve this using a thread map to long[]
@@ -34,12 +34,26 @@ public class VerticalLevelContainer implements LevelContainer
return true;
}
public boolean addSingleData(long newData, int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[posX][posZ][0] = newData;
return true;
}
public long[] getData(int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[posX][posZ];
}
public long getSingleData(int posX, int posZ){
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//Improve this using a thread map to long[]
return dataContainer[posX][posZ][0];
}
public boolean doesItExist(int posX, int posZ){
long[] data = getData(posX,posZ);
if(data == null)
+32 -33
View File
@@ -84,7 +84,7 @@ public class LodUtil
public static final byte DETAIL_OPTIONS = 10;
public static final short MAX_VERTICAL_DATA = 256;
public static final short MAX_VERTICAL_DATA = 4;
/** measured in Blocks <br>
* detail level 9 */
@@ -326,41 +326,40 @@ public class LodUtil
* Get a HashSet of all ChunkPos within the normal render distance
* that should not be rendered.
*/
public static HashSet<ChunkPos> getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos)
{
int chunkRenderDist = mc.getRenderDistance();
ChunkPos centerChunk = new ChunkPos(playerPos);
// skip chunks that are already going to be rendered by Minecraft
HashSet<ChunkPos> posToSkip = getRenderedChunks();
// go through each chunk within the normal view distance
for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++)
{
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
{
if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z))
continue;
/*
long[] dataVertical = lodDim.getData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
long data = dataVertical[dataVertical.length - 1];
public static HashSet<ChunkPos> getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos)
{
int chunkRenderDist = mc.getRenderDistance();
ChunkPos centerChunk = new ChunkPos(playerPos);
short lodAverageHeight = DataPointUtil.getHeight(data);
// skip chunks that are already going to be rendered by Minecraft
HashSet<ChunkPos> posToSkip = getRenderedChunks();
if (playerPos.getY() <= lodAverageHeight)
{
// don't draw Lod's that are taller than the player
// to prevent LODs being drawn on top of the player
posToSkip.add(new ChunkPos(x, z));
}*/
posToSkip.add(new ChunkPos(x, z));
}
}
return posToSkip;
}
// go through each chunk within the normal view distance
for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++)
{
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
{
if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z))
continue;
/**
long data = lodDim.getSingleData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
short lodAverageHeight = DataPointUtil.getHeight(data);
if (playerPos.getY() <= lodAverageHeight)
{
// don't draw Lod's that are taller than the player
// to prevent LODs being drawn on top of the player
posToSkip.add(new ChunkPos(x, z));
}
}
}
return posToSkip;
}
/**
* This method returns the ChunkPos of all chunks that Minecraft
* is going to render this frame. <br><br>
* <p>
@@ -5,48 +5,56 @@ import java.util.concurrent.ConcurrentMap;
public class ThreadMapUtil
{
public static final ConcurrentMap<String,long[]> threadSingleAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadSingleGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadSingleUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[][]> threadBuilderArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[][][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadVerticalAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> threadVerticalGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[][]> threadVerticalUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,int[]> threadVerticalIndexesMap = new ConcurrentHashMap();
private static final int NUMBER_OF_DIRECTION = 4;
public static final ConcurrentMap<String, long[]> threadSingleAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadSingleGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadSingleUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[][]> threadBuilderArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[][][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadVerticalAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadVerticalGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[][]> threadVerticalUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, int[]> threadVerticalIndexesMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,boolean[]> projectionMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,int[][]> heightAndDepthMap = new ConcurrentHashMap();
public static final ConcurrentMap<String,long[]> singleDataToMergeMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadAdjData = new ConcurrentHashMap();
public static final ConcurrentMap<String, boolean[]> projectionMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, int[][]> heightAndDepthMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap();
public static long[] getSingleAddDataArray(){
if(!threadSingleAddDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleAddDataMap.get(Thread.currentThread().getName()) == null))
public static long[] getSingleAddDataArray()
{
if (!threadSingleAddDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleAddDataMap.get(Thread.currentThread().getName()) == null))
{
threadSingleAddDataMap.put(Thread.currentThread().getName(), new long[1]);
}
return threadSingleAddDataMap.get(Thread.currentThread().getName());
}
public static long[] getSingleGetDataArray(){
if(!threadSingleGetDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleGetDataMap.get(Thread.currentThread().getName()) == null))
public static long[] getSingleGetDataArray()
{
if (!threadSingleGetDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleGetDataMap.get(Thread.currentThread().getName()) == null))
{
threadSingleGetDataMap.put(Thread.currentThread().getName(), new long[1]);
}
return threadSingleGetDataMap.get(Thread.currentThread().getName());
}
public static long[] getSingleUpdateArray(){
if(!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null))
public static long[] getSingleUpdateArray()
{
if (!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null))
{
threadSingleUpdateMap.put(Thread.currentThread().getName(), new long[4]);
}
return threadSingleUpdateMap.get(Thread.currentThread().getName());
}
public static long[][] getBuilderArray(){
if(!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null))
public static long[][] getBuilderArray()
{
if (!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[5][];
threadBuilderArrayMap.put(Thread.currentThread().getName(), array);
@@ -54,8 +62,9 @@ public class ThreadMapUtil
return threadBuilderArrayMap.get(Thread.currentThread().getName());
}
public static long[][][] getBuilderVerticalArray(){
if(!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null))
public static long[][][] getBuilderVerticalArray()
{
if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null))
{
long[][][] array = new long[5][][];
threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array);
@@ -63,22 +72,33 @@ public class ThreadMapUtil
return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName());
}
public static long[] addVerticalDataArray(){
if(!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null))
public static long[] addVerticalDataArray()
{
if (!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[16]);
}
return threadVerticalAddDataMap.get(Thread.currentThread().getName());
}
public static long[] getVerticalGetDataArray(){
if(!threadVerticalGetDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalGetDataMap.get(Thread.currentThread().getName()) == null))
public static long[] getVerticalGetDataArray()
{
if (!threadVerticalGetDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalGetDataMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalGetDataMap.put(Thread.currentThread().getName(), new long[16]);
}
return threadVerticalGetDataMap.get(Thread.currentThread().getName());
}
public static long[] getAdjDataArray()
{
if(!threadAdjData.containsKey(Thread.currentThread().getName()) || (threadAdjData.get(Thread.currentThread().getName()) == null))
{
threadAdjData.put(Thread.currentThread().getName(), new long[NUMBER_OF_DIRECTION]);
}
return threadAdjData.get(Thread.currentThread().getName());
}
public static long[][] getVerticalUpdateArray(){
if(!threadVerticalUpdateMap.containsKey(Thread.currentThread().getName()) || (threadVerticalUpdateMap.get(Thread.currentThread().getName()) == null))
{