Compare commits

...

10 Commits

Author SHA1 Message Date
cola98765 2834a73551 fix fog for fixed render distance 2021-12-10 20:06:22 +01:00
cola98765 5a7af89f5c fix calculation of view range. if it was k*32+x where k is int and 0<=x<16. To compare with old versions add 32 2021-12-10 20:06:14 +01:00
cola98765 eff491127b changed debug key to F8 and added chat messages when using debug keys. 2021-12-10 20:06:04 +01:00
Morippi 61502c32a6 fixewd generation not working 2021-12-10 19:18:22 +01:00
Morippi b7911ec4c8 Removed most of BlockPos and ChunkPos use 2021-12-10 19:05:27 +01:00
cola98765 1115c5f6c5 moved merge works now 19min on my PC 2021-12-10 09:28:10 +01:00
Morippi 5d001bf7ea changed some parameters 2021-12-09 20:26:19 +01:00
Morippi 4e732f7916 added a parameter 2021-12-09 20:25:55 +01:00
Morippi 30d392f861 Added field name and methods name for the merge 2021-12-09 20:25:01 +01:00
cola98765 f8910b0c3b move the merge 2021-12-09 19:59:50 +01:00
22 changed files with 559 additions and 222 deletions
@@ -184,14 +184,16 @@ public class EventApi
{
if (CONFIG.client().advanced().debugging().getDebugKeybindingsEnabled())
{
if (key == GLFW.GLFW_KEY_F4 && keyAction == GLFW.GLFW_PRESS)
if (key == GLFW.GLFW_KEY_F8 && keyAction == GLFW.GLFW_PRESS)
{
CONFIG.client().advanced().debugging().setDebugMode(CONFIG.client().advanced().debugging().getDebugMode().getNext());
MC.sendChatMessage("F8: Set debug mode " + CONFIG.client().advanced().debugging().getDebugMode());
}
if (key == GLFW.GLFW_KEY_F6 && keyAction == GLFW.GLFW_PRESS)
{
CONFIG.client().advanced().debugging().setDrawLods(!CONFIG.client().advanced().debugging().getDrawLods());
MC.sendChatMessage("F6: Set rendering " + CONFIG.client().advanced().debugging().getDrawLods());
}
}
}
@@ -222,7 +224,7 @@ public class EventApi
int newWidth = (int) Math.ceil(chunksWide / (float) LodUtil.REGION_WIDTH_IN_CHUNKS);
// make sure we have an odd number of regions
newWidth += (newWidth & 1) == 0 ? 1 : 2;
newWidth += (newWidth & 1) == 0 ? 1 : 0;
// do the dimensions need to change in size?
if (ApiShared.lodBuilder.defaultDimensionWidthInRegions != newWidth || recalculateWidths)
@@ -30,6 +30,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import com.seibel.lod.core.enums.config.LodTemplate;
import net.minecraft.util.math.BlockPos;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
@@ -144,14 +146,17 @@ public class LodBufferBuilderFactory
private volatile VertexOptimizer[][] vertexOptimizerCache;
private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center;
private volatile int centerRegionX = 0;
private volatile int centerRegionZ = 0;
/**
* This is the ChunkPosWrapper the player was at the last time the buffers were built.
* IE the center of the buffers last time they were built
*/
private volatile AbstractChunkPosWrapper drawableCenterChunkPos = WRAPPER_FACTORY.createChunkPos();
private volatile AbstractChunkPosWrapper buildableCenterChunkPos = WRAPPER_FACTORY.createChunkPos();
private volatile int drawableCenterChunkPosX = 0;
private volatile int drawableCenterChunkPosZ = 0;
private volatile int buildableCenterChunkPosX = 0;
private volatile int buildableCenterChunkPosZ = 0;
@@ -173,7 +178,7 @@ public class LodBufferBuilderFactory
* swapped with the drawable buffers in the LodRenderer to be drawn.
*/
public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim,
AbstractBlockPosWrapper playerBlockPos, boolean fullRegen)
int playerX, int playerY, int playerZ, boolean fullRegen)
{
// only allow one generation process to happen at a time
@@ -191,7 +196,7 @@ public class LodBufferBuilderFactory
generatingBuffers = true;
Thread thread = new Thread(() -> generateLodBuffersThread(renderer, lodDim, playerBlockPos, fullRegen));
Thread thread = new Thread(() -> generateLodBuffersThread(renderer, lodDim, playerX, playerY, playerZ, fullRegen));
mainGenThread.execute(thread);
}
@@ -200,15 +205,17 @@ public class LodBufferBuilderFactory
// more easily edited by hot swapping. Because, As far as James is aware
// you can't hot swap lambda expressions.
private void generateLodBuffersThread(LodRenderer renderer, LodDimension lodDim,
AbstractBlockPosWrapper playerBlockPos, boolean fullRegen)
int playerX, int playerY, int playerZ, boolean fullRegen)
{
bufferLock.lock();
try
{
// round the player's block position down to the nearest chunk BlockPos
AbstractChunkPosWrapper playerChunkPos = WRAPPER_FACTORY.createChunkPos(playerBlockPos);
AbstractBlockPosWrapper playerBlockPosRounded = playerChunkPos.getWorldPosition();
int playerChunkX = LevelPosUtil.convert(LodUtil.BLOCK_DETAIL_LEVEL,playerX,LodUtil.CHUNK_DETAIL_LEVEL);
int playerChunkZ = LevelPosUtil.convert(LodUtil.BLOCK_DETAIL_LEVEL,playerZ,LodUtil.CHUNK_DETAIL_LEVEL);
int playerRegionX = LevelPosUtil.convert(LodUtil.BLOCK_DETAIL_LEVEL,playerX,LodUtil.REGION_DETAIL_LEVEL);
int playerRegionZ = LevelPosUtil.convert(LodUtil.BLOCK_DETAIL_LEVEL,playerZ,LodUtil.REGION_DETAIL_LEVEL);
//long startTime = System.currentTimeMillis();
@@ -217,11 +224,6 @@ public class LodBufferBuilderFactory
startBuffers(fullRegen, lodDim);
RegionPos playerRegionPos = new RegionPos(playerChunkPos);
if (center == null)
center = playerRegionPos;
if (setsToRender == null)
setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()];
@@ -235,14 +237,15 @@ public class LodBufferBuilderFactory
vertexOptimizerCache = new VertexOptimizer[lodDim.getWidth()][lodDim.getWidth()];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
buildableCenterChunkPosX = playerChunkX;
buildableCenterChunkPosZ = playerChunkZ;
//================================//
// create the nodeToRenderThreads //
//================================//
skyLightPlayer = MC.getWrappedClientWorld().getSkyLight(playerBlockPos);
skyLightPlayer = MC.getWrappedClientWorld().getSkyLight(playerX, playerY, playerZ);
for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++)
{
@@ -308,8 +311,8 @@ public class LodBufferBuilderFactory
lodDim.getPosToRender(
posToRender,
regionPos,
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
playerX,
playerZ);
@@ -327,14 +330,14 @@ public class LodBufferBuilderFactory
posX = posToRender.getNthPosX(index);
posZ = posToRender.getNthPosZ(index);
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.getX();
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.getZ();
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkX;
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkZ;
//We don't want to render this fake block if
//The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered
//
//The block is in the player chunk or in a chunk adjacent to the player
if(isThisPositionGoingToBeRendered(detailLevel, posX, posZ, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance))
if(isThisPositionGoingToBeRendered(detailLevel, posX, posZ, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance))
{
continue;
}
@@ -355,8 +358,8 @@ public class LodBufferBuilderFactory
xAdj = posX + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).x;
zAdj = posZ + VertexOptimizer.DIRECTION_NORMAL_MAP.get(lodDirection).z;
long data;
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.getX();
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.getZ();
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkX;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkZ;
adjPosInPlayerChunk = (chunkXdist == 0 && chunkZdist == 0);
//If the adj block is rendered in the same region and with same detail
@@ -365,7 +368,7 @@ public class LodBufferBuilderFactory
// We avoid cases where the adjPosition is in player chunk while the position is not
// to always have a wall underwater
if(posToRender.contains(detailLevel, xAdj, zAdj)
&& !isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance)
&& !isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance)
&& !(posNotInPlayerChunk && adjPosInPlayerChunk))
{
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++)
@@ -382,7 +385,7 @@ public class LodBufferBuilderFactory
adjData.get(lodDirection)[0] = DataPointUtil.EMPTY_DATA;
if ((isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance) || (posNotInPlayerChunk && adjPosInPlayerChunk))
if ((isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance) || (posNotInPlayerChunk && adjPosInPlayerChunk))
&& !DataPointUtil.isVoid(data))
{
adjShadeDisabled[VertexOptimizer.DIRECTION_INDEX.get(lodDirection)] = DataPointUtil.getAlpha(data) < 255;
@@ -418,7 +421,7 @@ public class LodBufferBuilderFactory
break;
//We send the call to create the vertices
CONFIG.client().graphics().advancedGraphics().getLodTemplate().template.addLodToBuffer(currentBuffers[bufferIndex], playerBlockPosRounded, data, adjData,
LodTemplate.CUBIC.template.addLodToBuffer(currentBuffers[bufferIndex], playerX, playerY, playerZ, data, adjData,
detailLevel, posX, posZ, vertexOptimizer, renderer.previousDebugMode, adjShadeDisabled);
}
@@ -488,12 +491,12 @@ public class LodBufferBuilderFactory
}
}
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, AbstractChunkPosWrapper playerChunkPos, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, int chunkPosX, int chunkPosZ, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
// skip any chunks that Minecraft is going to render
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.getX();
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.getZ();
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - chunkPosX;
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - chunkPosZ;
// check if the chunk is on the border
boolean isItBorderPos;
@@ -1016,7 +1019,8 @@ public class LodBufferBuilderFactory
drawableStorageBufferIds = buildableStorageBufferIds;
buildableStorageBufferIds = tmpStorage;
drawableCenterChunkPos = buildableCenterChunkPos;
drawableCenterChunkPosX = buildableCenterChunkPosX;
drawableCenterChunkPosZ = buildableCenterChunkPosZ;
// the vbos have been swapped
switchVbos = false;
@@ -1032,7 +1036,7 @@ public class LodBufferBuilderFactory
}
}
return new VertexBuffersAndOffset(drawableVbos, drawableStorageBufferIds, drawableCenterChunkPos);
return new VertexBuffersAndOffset(drawableVbos, drawableStorageBufferIds, drawableCenterChunkPosX, drawableCenterChunkPosZ);
}
/** A simple container to pass multiple objects back in the getVertexBuffers method. */
@@ -1040,13 +1044,15 @@ public class LodBufferBuilderFactory
{
public final LodVertexBuffer[][][] vbos;
public final int[][][] storageBufferIds;
public final AbstractChunkPosWrapper drawableCenterChunkPos;
public int drawableCenterChunkPosX;
public int drawableCenterChunkPosZ;
public VertexBuffersAndOffset(LodVertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, AbstractChunkPosWrapper newDrawableCenterChunkPos)
public VertexBuffersAndOffset(LodVertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, int newDrawableCenterChunkPosX, int newDrawableCenterChunkPosZ)
{
vbos = newVbos;
storageBufferIds = newStorageBufferIds;
drawableCenterChunkPos = newDrawableCenterChunkPos;
drawableCenterChunkPosX = newDrawableCenterChunkPosX;
drawableCenterChunkPosZ = newDrawableCenterChunkPosZ;
}
}
@@ -37,7 +37,7 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public abstract class AbstractLodTemplate
{
/** Uploads the given LOD to the buffer. */
public abstract void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
public abstract void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled);
/** add the given position and color to the buffer */
@@ -27,7 +27,6 @@ import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
/**
* Builds LODs as rectangular prisms.
@@ -43,7 +42,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
@Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
public void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
if (vertexOptimizer == null)
@@ -65,7 +64,9 @@ public class CubicLodTemplate extends AbstractLodTemplate
DataPointUtil.getDepth(data),
blockWidth,
posX * blockWidth, 0, posZ * blockWidth, // x, y, z offset
bufferCenterBlockPos,
playerX,
playerY,
playerZ,
adjData,
color,
DataPointUtil.getLightSkyAlt(data),
@@ -78,7 +79,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
private void generateBoundingBox(VertexOptimizer vertexOptimizer,
int height, int depth, int width,
double xOffset, double yOffset, double zOffset,
AbstractBlockPosWrapper bufferCenterBlockPos,
int playerX, int playerY, int playerZ,
Map<LodDirection, long[]> adjData,
int color, byte skyLight, byte blockLight,
boolean[] adjShadeDisabled)
@@ -95,14 +96,13 @@ public class CubicLodTemplate extends AbstractLodTemplate
// offset the AABB by its x/z position in the world since
// it uses doubles to specify its location, unlike the model view matrix
// which only uses floats
double x = -bufferCenterBlockPos.getX();
double z = -bufferCenterBlockPos.getZ();
double x = -playerX;
double z = -playerZ;
vertexOptimizer.reset();
vertexOptimizer.setColor(color, adjShadeDisabled);
vertexOptimizer.setLights(skyLight, blockLight);
vertexOptimizer.setWidth(width, height - depth, width);
vertexOptimizer.setOffset((int) (xOffset + x), (int) (depth + yOffset), (int) (zOffset + z));
vertexOptimizer.setUpCulling(32, bufferCenterBlockPos);
vertexOptimizer.setAdjData(adjData);
}
@@ -113,9 +113,6 @@ public class CubicLodTemplate extends AbstractLodTemplate
byte blockLight;
for (LodDirection lodDirection : VertexOptimizer.DIRECTIONS)
{
if(vertexOptimizer.isCulled(lodDirection))
continue;
int verticalFaceIndex = 0;
while (vertexOptimizer.shouldRenderFace(lodDirection, verticalFaceIndex))
{
@@ -39,7 +39,7 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public class DynamicLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
public void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
@@ -37,7 +37,7 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public class TriangularLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, long data, Map<LodDirection, long[]> adjData,
public void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
@@ -170,7 +170,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
int startZ;
LodRegion region = lodDim.getRegion(chunk.getPos().getRegionX(), chunk.getPos().getRegionZ());
LodRegion region = lodDim.getRegion(chunk.getRegionPosX(), chunk.getRegionPosZ());
if (region == null)
return;
@@ -198,18 +198,11 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
long[] data;
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.length != 0)
{
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().getX() * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().getZ() * 16 + startZ, detail.detailLevel);
lodDim.addVerticalData(detailLevel, posX, posZ, data, false);
}
posX = LevelPosUtil.convert((byte) 0, chunk.getChunkPosX() * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getChunkPosZ() * 16 + startZ, detail.detailLevel);
lodDim.mergeMultiData(detailLevel, posX, posZ, false, dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1);
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().getX(), chunk.getPos().getZ());
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getChunkPosX(), chunk.getChunkPosZ());
//executeTime = System.currentTimeMillis() - executeTime;
//if (executeTime > 0) ClientApi.LOGGER.info("generateLodNodeFromChunk level: " + detailLevel + " time ms: " + executeTime);
}
@@ -222,8 +215,6 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail.detailLevel);
int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
AbstractChunkPosWrapper chunkPos = chunk.getPos();
int height;
int depth;
int color;
@@ -240,23 +231,22 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
boolean hasCeiling = MC.getWrappedClientWorld().getDimensionType().hasCeiling();
boolean hasSkyLight = MC.getWrappedClientWorld().getDimensionType().hasSkyLight();
boolean isDefault;
AbstractBlockPosWrapper blockPos = FACTORY.createBlockPos();
int index;
for (index = 0; index < size * size; index++)
{
xRel = startX + index % size;
zRel = startZ + index / size;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
xAbs = chunk.getMinX() + xRel;
zAbs = chunk.getMinZ() + zRel;
//Calculate the height of the lod
yAbs = DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET + 1;
yAbs = chunk.getMaxY(xRel, zRel); //DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET + 1;
int count = 0;
boolean topBlock = true;
while (yAbs > 0)
{
height = determineHeightPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
height = determineHeightPointFrom(chunk, config, xAbs, yAbs, zAbs);
// If the lod is at the default height, it must be void data
if (height == DEFAULT_HEIGHT)
@@ -268,21 +258,17 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
yAbs = height - 1;
// We search light on above air block
depth = determineBottomPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
depth = determineBottomPointFrom(chunk, config, xAbs, yAbs, zAbs);
if (hasCeiling && topBlock)
{
yAbs = depth;
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, true, hasSkyLight, true);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs, blockPos);
blockPos.set(xAbs, yAbs - 1, zAbs);
light = getLightValue(chunk, xAbs,yAbs,zAbs, true, hasSkyLight, true);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs);
}
else
{
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, topBlock);
color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos);
blockPos.set(xAbs, yAbs + 1, zAbs);
light = getLightValue(chunk, xAbs, yAbs, zAbs, hasCeiling, hasSkyLight, topBlock);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs);
}
lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111;
@@ -301,14 +287,13 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
* Find the lowest valid point from the bottom.
* Used when creating a vertical LOD.
*/
private short determineBottomPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, AbstractBlockPosWrapper blockPos)
private short determineBottomPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs)
{
short depth = DEFAULT_DEPTH;
for (int y = yAbs; y >= 0; y--)
{
blockPos.set(xAbs, y, zAbs);
if (!isLayerValidLodPoint(chunk, blockPos))
if (!isLayerValidLodPoint(chunk, xAbs, y, zAbs))
{
depth = (short) (y + 1);
break;
@@ -318,8 +303,9 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
}
/** Find the highest valid point from the Top */
private short determineHeightPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, AbstractBlockPosWrapper blockPos)
private short determineHeightPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs)
{
short height = DEFAULT_HEIGHT;
if (config.useHeightmap)
height = (short) chunk.getHeightMapValue(xAbs, zAbs);
@@ -327,8 +313,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
{
for (int y = yAbs; y >= 0; y--)
{
blockPos.set(xAbs, y, zAbs);
if (isLayerValidLodPoint(chunk, blockPos))
if (isLayerValidLodPoint(chunk, xAbs, y, zAbs))
{
height = (short) (y + 1);
break;
@@ -348,19 +333,18 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
* Generate the color for the given chunk using biome water color, foliage
* color, and grass color.
*/
private int generateLodColor(IChunkWrapper chunk, LodBuilderConfig builderConfig, int xRel, int yAbs, int zRel, AbstractBlockPosWrapper blockPos)
private int generateLodColor(IChunkWrapper chunk, LodBuilderConfig builderConfig, int x, int y, int z)
{
int colorInt;
if (builderConfig.useBiomeColors)
{
// I have no idea why I need to bit shift to the right, but
// if I don't the biomes don't show up correctly.
colorInt = chunk.getBiome(xRel, yAbs, zRel).getColorForBiome(xRel, zRel);
colorInt = chunk.getBiome(x, y, z).getColorForBiome(x, z);
}
else
{
blockPos.set(chunk.getPos().getMinBlockX() + xRel, yAbs, chunk.getPos().getMinBlockZ() + zRel);
colorInt = getColorForBlock(chunk, blockPos);
colorInt = getColorForBlock(chunk, x, y, z);
// if we are skipping non-full and non-solid blocks that means we ignore
// snow, flowers, etc. Get the above block so we can still get the color
@@ -368,8 +352,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
int aboveColorInt = 0;
if (config.client().worldGenerator().getBlocksToAvoid().nonFull || config.client().worldGenerator().getBlocksToAvoid().noCollision)
{
blockPos.set(chunk.getPos().getMinBlockX() + xRel, yAbs + 1, chunk.getPos().getMinBlockZ() + zRel);
aboveColorInt = getColorForBlock(chunk, blockPos);
aboveColorInt = getColorForBlock(chunk, x, y, z);
}
//if (colorInt == 0 && yAbs > 0)
@@ -386,7 +369,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
}
/** Gets the light value for the given block position */
private int getLightValue(IChunkWrapper chunk, AbstractBlockPosWrapper blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
private int getLightValue(IChunkWrapper chunk, int x, int y, int z, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
{
int skyLight = 0;
int blockLight;
@@ -395,25 +378,25 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
IWorldWrapper world = MC.getWrappedServerWorld();
int blockBrightness = chunk.getEmittedBrightness(blockPos);
int blockBrightness = chunk.getEmittedBrightness(x, y, z);
// get the air block above or below this block
if (hasCeiling && topBlock)
blockPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
y--;
else
blockPos.set(blockPos.getX(), blockPos.getY() + 1, blockPos.getZ());
y++;
if (world != null)
{
// server world sky light (always accurate)
blockLight = world.getBlockLight(blockPos);
blockLight = world.getBlockLight(x,y,z);
if (topBlock && !hasCeiling && hasSkyLight)
skyLight = DEFAULT_MAX_LIGHT;
else
{
if (hasSkyLight)
skyLight = world.getSkyLight(blockPos);
skyLight = world.getSkyLight(x,y,z);
//else
// skyLight = 0;
}
@@ -421,7 +404,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
{
// we are on predicted terrain, and we don't know what the light here is,
// lets just take a guess
if (blockPos.getY() >= MC.getWrappedClientWorld().getSeaLevel() - 5)
if (y >= MC.getWrappedClientWorld().getSeaLevel() - 5)
{
skyLight = 12;
isDefault = 1;
@@ -442,7 +425,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
else
{
// client world sky light (almost never accurate)
blockLight = world.getBlockLight(blockPos);
blockLight = world.getBlockLight(x,y,z);
// estimate what the lighting should be
if (hasSkyLight || !hasCeiling)
{
@@ -451,14 +434,14 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
else
{
if (hasSkyLight)
skyLight = world.getSkyLight(blockPos);
skyLight = world.getSkyLight(x,y,z);
//else
// skyLight = 0;
if (!chunk.isLightCorrect() && (skyLight == 0 || skyLight == 15))
{
// we don't know what the light here is,
// lets just take a guess
if (blockPos.getY() >= MC.getWrappedClientWorld().getSeaLevel() - 5)
if (y >= MC.getWrappedClientWorld().getSeaLevel() - 5)
{
skyLight = 12;
isDefault = 1;
@@ -477,24 +460,19 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
}
/** Returns a color int for the given block. */
private int getColorForBlock(IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
private int getColorForBlock(IChunkWrapper chunk, int x, int y, int z)
{
int colorOfBlock;
int colorInt;
int xRel = blockPos.getX() - chunk.getPos().getMinBlockX();
int zRel = blockPos.getZ() - chunk.getPos().getMinBlockZ();
//int x = blockPos.getX();
int y = blockPos.getY();
//int z = blockPos.getZ();
IBlockColorWrapper blockColorWrapper;
IBlockShapeWrapper blockShapeWrapper = chunk.getBlockShapeWrapper(blockPos);
IBlockShapeWrapper blockShapeWrapper = chunk.getBlockShapeWrapper(x, y, z);
if (chunk.isWaterLogged(blockPos))
if (chunk.isWaterLogged(x, y, z))
blockColorWrapper = BLOCK_COLOR.getWaterColor();
else
blockColorWrapper = chunk.getBlockColorWrapper(blockPos);
blockColorWrapper = chunk.getBlockColorWrapper(x, y, z);
if (blockShapeWrapper.isToAvoid())
return 0;
@@ -504,7 +482,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
if (blockColorWrapper.hasTint())
{
IBiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
IBiomeWrapper biome = chunk.getBiome(x, y, z);
int tintValue;
if (blockColorWrapper.hasGrassTint())
// grass and green plants
@@ -524,15 +502,15 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
/** Is the block at the given blockPos a valid LOD point? */
private boolean isLayerValidLodPoint(IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
private boolean isLayerValidLodPoint(IChunkWrapper chunk, int x, int y, int z)
{
if (chunk.isWaterLogged(blockPos))
if (chunk.isWaterLogged(x, y, z))
return true;
boolean nonFullAvoidance = config.client().worldGenerator().getBlocksToAvoid().nonFull;
boolean noCollisionAvoidance = config.client().worldGenerator().getBlocksToAvoid().noCollision;
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(blockPos);
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(x, y, z);
return !block.isToAvoid()
&& !(nonFullAvoidance && block.isNonFull())
&& !(noCollisionAvoidance && block.hasNoCollision());
@@ -126,7 +126,7 @@ public class LodGenWorker
@Override
public void run()
{
try
//try
{
// only generate LodChunks if they can
// be added to the current LodDimension
@@ -172,19 +172,19 @@ public class LodGenWorker
}// if in range
}
catch (Exception e)
{
ClientApi.LOGGER.error(LodChunkGenThread.class.getSimpleName() + ": ran into an error: " + e.getMessage());
e.printStackTrace();
}
finally
{
//catch (Exception e)
//{
// ClientApi.LOGGER.error(LodChunkGenThread.class.getSimpleName() + ": ran into an error: " + e.getMessage());
// e.printStackTrace();
//}
//finally
//{
// decrement how many threads are running
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.addAndGet(-1);
// this position is no longer being generated
LodWorldGenerator.INSTANCE.positionsWaitingToBeGenerated.remove(pos);
}
//}
}// run
@@ -1,5 +0,0 @@
package com.seibel.lod.core.dataFormat;
public class DataMerger
{
}
@@ -40,12 +40,21 @@ public class PositionDataFormat
return positionData;
}
public static String toString(short verticalData, short positionData)
{
return getLodCount(verticalData) + " " +
getLightFlag(verticalData) + " " +
getGenerationMode(verticalData) + " " +
isVoid(verticalData) + " " +
doesItExist(verticalData) + " " +'\n';
}
public static byte getLodCount(short dataPoint)
{
return (byte) ((dataPoint >>> LOD_COUNT_SHIFT) & LOD_COUNT_MASK);
}
public static boolean getFlag(short dataPoint)
public static boolean getLightFlag(short dataPoint)
{
return ((dataPoint >>> CORRECT_LIGHT_SHIFT) & CORRECT_LIGHT_MASK) == 1;
}
@@ -4,6 +4,7 @@ public class VerticalDataFormat
{
public final static short MIN_WORLD_HEIGHT = -2048;
public final static short MAX_WORLD_HEIGHT = 2047;
public final static short WORLD_HEIGHT = MAX_WORLD_HEIGHT - MIN_WORLD_HEIGHT;
public final static byte HEIGHT_SHIFT = 20;
public final static byte DEPTH_SHIFT = 8;
@@ -25,8 +26,8 @@ public class VerticalDataFormat
public static int createVerticalData(int height, int depth, int level, boolean transparent, boolean bottom)
{
int verticalData = 0;
verticalData |= (height & HEIGHT_MASK) << HEIGHT_SHIFT;
verticalData |= (depth & DEPTH_MASK) << DEPTH_SHIFT;
verticalData |= ((height - MIN_WORLD_HEIGHT) & HEIGHT_MASK) << HEIGHT_SHIFT;
verticalData |= ((depth - MIN_WORLD_HEIGHT) & DEPTH_MASK) << DEPTH_SHIFT;
verticalData |= (level & LEVEL_MASK) << LEVEL_SHIFT;
if (bottom)
verticalData |= BOTTOM_TYPE_MASK << BOTTOM_TYPE_SHIFT;
@@ -37,14 +38,24 @@ public class VerticalDataFormat
return verticalData;
}
public static String toString(int verticalData, short positionData)
{
return getHeight(verticalData) + " " +
getDepth(verticalData) + " " +
getLevel(verticalData) + " " +
isTransparent(verticalData) + " " +
isBottom(verticalData) + " " +
doesItExist(verticalData) + " " + '\n';
}
public static short getHeight(int verticalData)
{
return (short) ((verticalData >>> HEIGHT_SHIFT) & HEIGHT_MASK);
return (short) (((verticalData >>> HEIGHT_SHIFT) & HEIGHT_MASK) + MIN_WORLD_HEIGHT);
}
public static short getDepth(int verticalData)
{
return (short) ((verticalData >>> DEPTH_SHIFT) & DEPTH_MASK);
return (short) (((verticalData >>> DEPTH_SHIFT) & DEPTH_MASK) + MIN_WORLD_HEIGHT);
}
public static byte getLevel(int verticalData)
@@ -200,8 +200,6 @@ public class VertexOptimizer
public final Map<LodDirection, byte[]> skyLights;
public byte blockLight;
/** Holds if the given direction should be culled or not */
public final boolean[] culling;
/** creates an empty box */
@@ -235,8 +233,6 @@ public class VertexOptimizer
put(LodDirection.SOUTH, new int[LodUtil.MAX_NUMBER_OF_VERTICAL_LODS]);
put(LodDirection.NORTH, new int[LodUtil.MAX_NUMBER_OF_VERTICAL_LODS]);
}};
culling = new boolean[6];
}
/** Set the light of the columns */
@@ -309,31 +305,6 @@ public class VertexOptimizer
}
}
/** determine which faces should be culled */
public void setUpCulling(int cullingDistance, AbstractBlockPosWrapper playerPos)
{
for (LodDirection lodDirection : DIRECTIONS)
{
if (lodDirection == LodDirection.DOWN || lodDirection == LodDirection.WEST || lodDirection == LodDirection.NORTH)
culling[DIRECTION_INDEX.get(lodDirection)] = playerPos.get(lodDirection.getAxis()) > getFacePos(lodDirection) + cullingDistance;
else if (lodDirection == LodDirection.UP || lodDirection == LodDirection.EAST || lodDirection == LodDirection.SOUTH)
culling[DIRECTION_INDEX.get(lodDirection)] = playerPos.get(lodDirection.getAxis()) < getFacePos(lodDirection) - cullingDistance;
culling[DIRECTION_INDEX.get(lodDirection)] = false;
}
}
/**
* @param lodDirection direction that we want to check if it's culled
* @return true if and only if the face of the direction is culled
*/
public boolean isCulled(LodDirection lodDirection)
{
return culling[DIRECTION_INDEX.get(lodDirection)];
}
/**
* This method create all the shared face culling based on the adjacent data
* @param adjData data adjacent to the column we are going to render
@@ -363,9 +334,6 @@ public class VertexOptimizer
//TODO clean some similar cases
for (LodDirection lodDirection : ADJ_DIRECTIONS)
{
if (isCulled(lodDirection))
continue;
long[] dataPoint = adjData.get(lodDirection);
if (dataPoint == null || DataPointUtil.isVoid(dataPoint[0]))
{
@@ -520,17 +488,6 @@ public class VertexOptimizer
boxOffset[Z] = zOffset;
}
/**
* This method return the position of a face in the axis of the face
* This is useful for the face culling
* @param lodDirection that we want to check
* @return position in the axis of the face
*/
public int getFacePos(LodDirection lodDirection)
{
return boxOffset[FACE_DIRECTION.get(lodDirection)[0]] + boxWidth[FACE_DIRECTION.get(lodDirection)[0]] * FACE_DIRECTION.get(lodDirection)[1];
}
/**
* returns true if the given direction should be rendered.
*/
@@ -112,4 +112,6 @@ public interface LevelContainer
* @return data as a String
*/
int getMaxNumberOfLods();
void mergeMultiData(int posX, int posZ, long[] dataToMergeVertical, int inputVerticalData);
}
@@ -909,4 +909,39 @@ public class LodDimension
{
isRegionDirty[i][j] = val;
}
public void mergeMultiData(byte detailLevel, int posX, int posZ, boolean dontSave, long[] dataToMergeVertical, int inputVerticalData)
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
// don't continue if the region can't be saved
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return;
region.mergeMultiData(detailLevel, posX, posZ, dataToMergeVertical, inputVerticalData);
// 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;
regenRegionBuffer[xIndex][zIndex] = true;
regenDimensionBuffers = true;
}
catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
// If this happens, the method was probably
// called when the dimension was changing size.
// Hopefully this shouldn't be an issue.
}
}
}
}
@@ -610,4 +610,16 @@ public class LodRegion
{
return getLevel(LodUtil.REGION_DETAIL_LEVEL).toString();
}
public void mergeMultiData(byte detailLevel, int posX, int posZ, long[] dataToMergeVertical, int inputVerticalData)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
// The dataContainer could have null entries if the
// detailLevel changes.
if (this.dataContainer[detailLevel] == null)
this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
this.dataContainer[detailLevel].mergeMultiData(posX, posZ, dataToMergeVertical, inputVerticalData);
}
}
@@ -19,6 +19,7 @@
package com.seibel.lod.core.objects.lod;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.LevelPosUtil;
@@ -35,10 +36,22 @@ public class VerticalLevelContainer implements LevelContainer
public final byte detailLevel;
public final int size;
public final int chunkCount = 0;
public final int chunkSize = 0;
public final int maxVerticalData;
public final long[] dataContainer;
//length should be chunkCount
public final byte[] verticalSize = null;
//length should be chunkCount
public final short[] positionData = null;
public final int[][] verticalData = null;
public final int[][] colorData = null;
public final byte[][] lightData = null;
public VerticalLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
@@ -196,7 +209,6 @@ public class VerticalLevelContainer implements LevelContainer
int lowerMaxVertical = dataToMerge.length / 4;
int childPosX;
int childPosZ;
long[] data;
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
@@ -207,9 +219,7 @@ public class VerticalLevelContainer implements LevelContainer
dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
}
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData());
addVerticalData(data, posX, posZ);
mergeMultiData(posX, posZ, dataToMerge, lowerMaxVertical);
}
@Override
@@ -244,6 +254,325 @@ public class VerticalLevelContainer implements LevelContainer
return tempData;
}
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;
}
}
/**
*
* @param positionDataToMerge
* @effect
*/
public void computePositionData(short[] positionDataToMerge)
{
}
/**
*
* @param verticalDataToMerge
* @param maxVerticalData max vertical size of the merged data
* @effect save in
*/
public void computeHeightAndDepthData(int[] verticalDataToMerge, int maxVerticalData)
{
}
/**
*
* @param colorDataToMerge
* @param lightDataToMerge
* @effect
*/
public void computeColorLightVerticalData(int[] colorDataToMerge, byte[] lightDataToMerge, int[] verticalDataToMerge)
{
}
/**
* This method merge column of multiple data together
* @param dataToMerge one or more columns of data
* @param inputVerticalData vertical size of an input data
*/
public void mergeMultiData(int posX, int posZ, long[] dataToMerge, int inputVerticalData)
{
int size = dataToMerge.length / inputVerticalData;
final int arrayPos = (posX * this.size + posZ) * maxVerticalData;
// We initialize the arrays that are going to be used
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((DataPointUtil.WORLD_HEIGHT / 2 + 1) * 2);
int genMode = DistanceGenerationMode.FULL.complexity;
boolean allEmpty = true;
boolean allVoid = true;
boolean allDefault;
long singleData;
short depth;
short height;
int count = 0;
int i;
int ii;
int dataIndex;
//We collect the indexes of the data, ordered by the depth
for (int index = 0; index < size; index++)
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (DataPointUtil.doesItExist(singleData))
{
genMode = Math.min(genMode, DataPointUtil.getGenerationMode(singleData));
allEmpty = false;
if (!DataPointUtil.isVoid(singleData))
{
allVoid = false;
depth = DataPointUtil.getDepth(singleData);
height = DataPointUtil.getHeight(singleData);
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
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
shrinkArray(heightAndDepth, 2, 0, botPos, count);
heightAndDepth[0] = height;
count -= botPos;
}
else
{
//top falls between some blocks, extending those as well
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;
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];
shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
}
else
{
//both top and bottom are outside existing blocks
shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
extendArray(heightAndDepth, 2, topPos + 1, 1, count);
count++;
heightAndDepth[topPos * 2 + 2] = height;
heightAndDepth[topPos * 2 + 3] = depth;
}
}
}
}
else
break;
}
}
//We check if there is any data that's not empty or void
if (allEmpty)
return;
if (allVoid)
{
dataContainer[arrayPos] = DataPointUtil.createVoidDataPoint(genMode);
return;
}
//we limit the vertical portion to maxVerticalData
int j = 0;
while (count > maxVerticalData)
{
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--;
}
//As standard the vertical lods are ordered from top to bottom
for (j = count - 1; j >= 0; j--)
{
if (j >= heightAndDepth.length / 2)
break;
height = heightAndDepth[j * 2];
depth = heightAndDepth[j * 2 + 1];
if ((depth == 0 && height == 0))
break;
int numberOfChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempLightBlock = 0;
int tempLightSky = 0;
byte tempGenMode = DistanceGenerationMode.FULL.complexity;
allEmpty = true;
allVoid = true;
allDefault = true;
long data = 0;
for (int index = 0; index < size; index++)
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (DataPointUtil.doesItExist(singleData) && !DataPointUtil.isVoid(singleData))
{
if ((depth <= DataPointUtil.getDepth(singleData) && DataPointUtil.getDepth(singleData) <= height)
|| (depth <= DataPointUtil.getHeight(singleData) && DataPointUtil.getHeight(singleData) <= height))
{
if (DataPointUtil.getHeight(singleData) > DataPointUtil.getHeight(data))
data = singleData;
}
}
else
break;
}
if (!DataPointUtil.doesItExist(data))
{
singleData = dataToMerge[index * inputVerticalData];
data = DataPointUtil.createVoidDataPoint(DataPointUtil.getGenerationMode(singleData));
}
if (DataPointUtil.doesItExist(data))
{
allEmpty = false;
if (!DataPointUtil.isVoid(data))
{
numberOfChildren++;
allVoid = false;
tempAlpha += DataPointUtil.getAlpha(data);
tempRed += DataPointUtil.getRed(data);
tempGreen += DataPointUtil.getGreen(data);
tempBlue += DataPointUtil.getBlue(data);
tempLightBlock += DataPointUtil.getLightBlock(data);
tempLightSky += DataPointUtil.getLightSky(data);
if (!DataPointUtil.getFlag(data)) allDefault = false;
}
tempGenMode = (byte) Math.min(tempGenMode, DataPointUtil.getGenerationMode(data));
}
else
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
}
if (allEmpty)
//no child has been initialized
dataContainer[arrayPos + j] = DataPointUtil.EMPTY_DATA;
else if (allVoid)
//all the children are void
dataContainer[arrayPos + j] = DataPointUtil.createVoidDataPoint(tempGenMode);
else
{
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
dataContainer[arrayPos + j] = DataPointUtil.createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
}
}
}
@Override
@SuppressWarnings("unused")
public String toString()
@@ -22,6 +22,7 @@ package com.seibel.lod.core.render;
import java.awt.Color;
import java.util.HashSet;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
@@ -49,8 +50,6 @@ import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
@@ -94,7 +93,8 @@ public class LodRenderer
@SuppressWarnings("unused")
private int[][][] storageBufferIds;
private AbstractChunkPosWrapper vbosCenter = FACTORY.createChunkPos();
private int vbosCenterX = 0;
private int vbosCenterZ = 0;
/** This is used to determine if the LODs should be regenerated */
@@ -193,7 +193,7 @@ public class LodRenderer
if ((partialRegen || fullRegen) && !lodBufferBuilderFactory.generatingBuffers && !lodBufferBuilderFactory.newBuffersAvailable())
{
// generate the LODs on a separate thread to prevent stuttering or freezing
lodBufferBuilderFactory.generateLodBuffersAsync(this, lodDim, MC.getPlayerBlockPos(), true);
lodBufferBuilderFactory.generateLodBuffersAsync(this, lodDim, MC.getPlayerBlockPos().getX(), MC.getPlayerBlockPos().getY(), MC.getPlayerBlockPos().getZ(), true);
// the regen process has been started,
// it will be done when lodBufferBuilder.newBuffersAvailable()
@@ -376,8 +376,10 @@ public class LodRenderer
boolean renderBufferStorage = CONFIG.client().advanced().buffers().getGpuUploadMethod() == GpuUploadMethod.BUFFER_STORAGE && glProxy.bufferStorageSupported;
// where the center of the buffers is (needed when culling regions)
RegionPos vboCenterRegionPos = new RegionPos(vbosCenter);
RegionPos vboPos = new RegionPos();
int vboCenterRegionPosX = vbosCenterX;
int vboCenterRegionPosZ = vbosCenterZ;
int vboPosX;
int vboPosZ;
// render each of the buffers
@@ -385,10 +387,13 @@ public class LodRenderer
{
for (int z = 0; z < vbos.length; z++)
{
vboPos.x = x + vboCenterRegionPos.x - (lodDim.getWidth() / 2);
vboPos.z = z + vboCenterRegionPos.z - (lodDim.getWidth() / 2);
vboPosX = x + vboCenterRegionPosX - (lodDim.getWidth() / 2);
vboPosZ = z + vboCenterRegionPosZ - (lodDim.getWidth() / 2);
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(MC_RENDER.getCameraBlockPosition(), MC_RENDER.getLookAtVector(), vboPos.blockPos()))
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(MC_RENDER.getCameraBlockPosition(),
MC_RENDER.getLookAtVector(),
LodUtil.convertLevelPos(LodUtil.REGION_DETAIL_LEVEL, vboPosX, LodUtil.BLOCK_DETAIL_LEVEL),
LodUtil.convertLevelPos(LodUtil.REGION_DETAIL_LEVEL, vboPosZ, LodUtil.BLOCK_DETAIL_LEVEL)))
{
// fog may be different from region to region
applyFog(shaderProgram,
@@ -531,12 +536,12 @@ public class LodRenderer
// far fog //
if (CONFIG.client().graphics().fogQuality().getFogDistance() == FogDistance.NEAR_AND_FAR)
fogConfig.farFogStart = farPlaneBlockDistance * 1.6f * 0.9f;
fogConfig.farFogStart = farPlaneBlockDistance * 0.9f;
else
// for more realistic fog when using FAR
fogConfig.farFogStart = Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f * 1.6f);
fogConfig.farFogStart = Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f);
fogConfig.farFogEnd = farPlaneBlockDistance * 1.6f;
fogConfig.farFogEnd = farPlaneBlockDistance;
// near fog //
@@ -579,9 +584,10 @@ public class LodRenderer
// translate the camera relative to the regions' center
// (AxisAlignedBoundingBoxes (LODs) use doubles and thus have a higher
// accuracy vs the model view matrix, which only uses floats)
AbstractBlockPosWrapper bufferPos = vbosCenter.getWorldPosition();
double xDiff = projectedView.x - bufferPos.getX();
double zDiff = projectedView.z - bufferPos.getZ();
int bufferPosX = LevelPosUtil.convert(LodUtil.REGION_DETAIL_LEVEL, vbosCenterX, LodUtil.CHUNK_DETAIL_LEVEL);
int bufferPosZ = LevelPosUtil.convert(LodUtil.REGION_DETAIL_LEVEL, vbosCenterZ, LodUtil.CHUNK_DETAIL_LEVEL);
double xDiff = projectedView.x - bufferPosX;
double zDiff = projectedView.z - bufferPosZ;
mcModelViewMatrix.multiplyTranslationMatrix(-xDiff, -projectedView.y, -zDiff);
return mcModelViewMatrix;
@@ -593,9 +599,10 @@ public class LodRenderer
*/
private Vec3f getTranslatedCameraPos()
{
AbstractBlockPosWrapper worldCenter = vbosCenter.getWorldPosition();
int worldCenterX = LevelPosUtil.convert(LodUtil.REGION_DETAIL_LEVEL, vbosCenterX, LodUtil.CHUNK_DETAIL_LEVEL);
int worldCenterZ = LevelPosUtil.convert(LodUtil.REGION_DETAIL_LEVEL, vbosCenterZ, LodUtil.CHUNK_DETAIL_LEVEL);
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
return new Vec3f((float)cameraPos.x - worldCenter.getX(), (float)cameraPos.y, (float)cameraPos.z - worldCenter.getZ());
return new Vec3f((float)cameraPos.x - worldCenterX, (float)cameraPos.y, (float)cameraPos.z - worldCenterZ);
}
/**
@@ -671,7 +678,8 @@ public class LodRenderer
VertexBuffersAndOffset result = lodBufferBuilderFactory.getVertexBuffers();
vbos = result.vbos;
storageBufferIds = result.storageBufferIds;
vbosCenter = result.drawableCenterChunkPos;
vbosCenterX = result.drawableCenterChunkPosX;
vbosCenterZ = result.drawableCenterChunkPosZ;
}
/** Calls the BufferBuilder's destroyBuffers method. */
@@ -85,11 +85,11 @@ public class RenderUtil
* Returns true if one of the region's 4 corners is in front
* of the camera.
*/
public static boolean isRegionInViewFrustum(AbstractBlockPosWrapper playerBlockPos, Vec3f cameraDir, AbstractBlockPosWrapper vboCenterPos)
public static boolean isRegionInViewFrustum(AbstractBlockPosWrapper playerBlockPos, Vec3f cameraDir, int vboCenterPosX, int vboCenterPosZ)
{
// convert the vbo position into a direction vector
// starting from the player's position
Vec3f vboVec = new Vec3f(vboCenterPos.getX(), 0, vboCenterPos.getZ());
Vec3f vboVec = new Vec3f(vboCenterPosX, 0, vboCenterPosZ);
Vec3f playerVec = new Vec3f(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ());
vboVec.subtract(playerVec);
@@ -263,6 +263,7 @@ public class DataPointUtil
* @param maxVerticalData max vertical size of the merged data
* @return one column of correctly parsed data
*/
@Deprecated
public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData)
{
int size = dataToMerge.length / inputVerticalData;
@@ -23,6 +23,8 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.forge.wrappers.block.BlockShapeWrapper;
import net.minecraft.block.Block;
/**
* @author James Seibel
@@ -32,21 +34,27 @@ public interface IChunkWrapper
{
int getHeight();
boolean isPositionInWater(AbstractBlockPosWrapper blockPos);
boolean isPositionInWater(int x, int y, int z);
int getHeightMapValue(int xRel, int zRel);
IBiomeWrapper getBiome(int xRel, int yAbs, int zRel);
IBiomeWrapper getBiome(int x, int y, int z);
IBlockColorWrapper getBlockColorWrapper(int x, int y, int z);
IBlockShapeWrapper getBlockShapeWrapper(int x, int y, int z);
IBlockColorWrapper getBlockColorWrapper(AbstractBlockPosWrapper blockPos);
IBlockShapeWrapper getBlockShapeWrapper(AbstractBlockPosWrapper blockPos);
AbstractChunkPosWrapper getPos();
int getChunkPosX();
int getChunkPosZ();
int getRegionPosX();
int getRegionPosZ();
int getMaxY(int x, int z);
int getMaxX();
int getMaxZ();
int getMinX();
int getMinZ();
boolean isLightCorrect();
boolean isWaterLogged(AbstractBlockPosWrapper blockPos);
boolean isWaterLogged(int x, int y, int z);
int getEmittedBrightness(AbstractBlockPosWrapper blockPos);
int getEmittedBrightness(int x, int y, int z);
}
@@ -184,17 +184,6 @@ public interface ILodConfigWrapperSingleton
{
String DESC = "Graphics options that are a bit more technical.";
LodTemplate LOD_TEMPLATE_DEFAULT = LodTemplate.CUBIC;
String LOD_TEMPLATE_DESC = ""
+ " How should the LODs be drawn? \n"
+ " NOTE: Currently only " + LodTemplate.CUBIC + " is implemented! \n"
+ " \n"
+ " " + LodTemplate.CUBIC + ": LOD Chunks are drawn as rectangular prisms (boxes). \n"
+ " " + LodTemplate.TRIANGULAR + ": LOD Chunks smoothly transition between other. \n"
+ " " + LodTemplate.DYNAMIC + ": LOD Chunks smoothly transition between each other, \n"
+ " " + " unless a neighboring chunk is at a significantly different height. \n";
LodTemplate getLodTemplate();
void setLodTemplate(LodTemplate newLodTemplate);
boolean DISABLE_DIRECTIONAL_CULLING_DEFAULT = false;
String DISABLE_DIRECTIONAL_CULLING_DESC = ""
@@ -451,7 +440,7 @@ public interface ILodConfigWrapperSingleton
boolean DEBUG_KEYBINDINGS_ENABLED_DEFAULT = true;
String DEBUG_KEYBINDINGS_ENABLED_DESC = ""
+ " If true the F4 key can be used to cycle through the different debug modes. \n"
+ " If true the F8 key can be used to cycle through the different debug modes. \n"
+ " and the F6 key can be used to enable and disable LOD rendering.";
boolean getDebugKeybindingsEnabled();
void setDebugKeybindingsEnabled(boolean newEnableDebugKeybindings);
@@ -36,11 +36,9 @@ public interface IWorldWrapper
WorldType getWorldType();
int getBlockLight(AbstractBlockPosWrapper blockPos);
int getBlockLight(int x, int y, int z);
int getSkyLight(AbstractBlockPosWrapper blockPos);
IBiomeWrapper getBiome(AbstractBlockPosWrapper blockPos);
int getSkyLight(int x, int y, int z);
boolean hasCeiling();