Compare commits

..

13 Commits

Author SHA1 Message Date
cola98765 1860729256 made this wokin with latest 1.16.5 2021-12-07 13:51:54 +01:00
cola98765 d0b0fae54e fix to that merge 2021-12-07 13:32:06 +01:00
Morippi 7786e1fea6 Change Box to VertexOptimizer and added the DataFormat folder with empty classes 2021-12-07 13:28:38 +01:00
cola98765 e5ad718ed0 fix LOWEST HorizontalQuality 2021-12-07 13:12:35 +01:00
cola98765 bda34d0a6d reverted DrawResolutionOffset 2021-12-07 13:12:22 +01:00
cola98765 2584afbd05 HorizontalScale is now a number 2-32 2021-12-07 13:12:14 +01:00
cola98765 72e4b520db updated DYNAMIC VanillaOverdraw setting. 2021-12-07 13:12:09 +01:00
cola98765 3220ad0f7a added DrawResolutionOffset to work with DrawResolution 2021-12-07 13:12:05 +01:00
James Seibel aba99f8210 Fix a few buffer building issues 2021-12-07 13:11:54 +01:00
Morippi 430579be28 Changed how data from the level container are passed as output. Removed the Thread system 2021-12-07 11:56:13 +01:00
cola98765 30cc294a04 reworked it back to primitive arrays 2021-12-04 14:03:01 +01:00
cola98765 aa79d5b5d4 small fix 2021-12-03 13:37:36 +01:00
cola98765 509ae5aba0 added new DataPoint. predicting is broken, and there are still couple errors in logs 2021-12-03 12:39:01 +01:00
41 changed files with 1041 additions and 2010 deletions
@@ -40,7 +40,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
* Specifically for the client.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-12-2021
*/
public class ClientApi
{
@@ -141,9 +141,6 @@ public class ClientApi
{
MC.sendChatMessage(ModInfo.READABLE_NAME + " experimental build " + ModInfo.VERSION);
MC.sendChatMessage("You are running a unsupported version of the mod!");
MC.sendChatMessage("==========================================");
MC.sendChatMessage("SEIZURE WARNING: Flashing lights expected!"); // remove this line when the lighting shaders are fixed
MC.sendChatMessage("==========================================");
MC.sendChatMessage("Here be dragons!");
configOverrideReminderPrinted = true;
@@ -184,16 +184,14 @@ public class EventApi
{
if (CONFIG.client().advanced().debugging().getDebugKeybindingsEnabled())
{
if (key == GLFW.GLFW_KEY_F8 && keyAction == GLFW.GLFW_PRESS)
if (key == GLFW.GLFW_KEY_F4 && 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());
}
}
}
@@ -224,7 +222,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 : 0;
newWidth += (newWidth & 1) == 0 ? 1 : 2;
// do the dimensions need to change in size?
if (ApiShared.lodBuilder.defaultDimensionWidthInRegions != newWidth || recalculateWidths)
@@ -30,8 +30,7 @@ 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 com.seibel.lod.core.objects.VertexOptimizer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
@@ -70,7 +69,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
* rendered by the LodRenderer.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-29-2021
*/
public class LodBufferBuilderFactory
{
@@ -146,17 +145,14 @@ public class LodBufferBuilderFactory
private volatile VertexOptimizer[][] vertexOptimizerCache;
private volatile PosToRenderContainer[][] setsToRender;
private volatile int centerRegionX = 0;
private volatile int centerRegionZ = 0;
private volatile RegionPos center;
/**
* 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 int drawableCenterChunkPosX = 0;
private volatile int drawableCenterChunkPosZ = 0;
private volatile int buildableCenterChunkPosX = 0;
private volatile int buildableCenterChunkPosZ = 0;
private volatile AbstractChunkPosWrapper drawableCenterChunkPos = WRAPPER_FACTORY.createChunkPos();
private volatile AbstractChunkPosWrapper buildableCenterChunkPos = WRAPPER_FACTORY.createChunkPos();
@@ -178,7 +174,7 @@ public class LodBufferBuilderFactory
* swapped with the drawable buffers in the LodRenderer to be drawn.
*/
public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim,
int playerX, int playerY, int playerZ, boolean fullRegen)
AbstractBlockPosWrapper playerBlockPos, boolean fullRegen)
{
// only allow one generation process to happen at a time
@@ -196,7 +192,7 @@ public class LodBufferBuilderFactory
generatingBuffers = true;
Thread thread = new Thread(() -> generateLodBuffersThread(renderer, lodDim, playerX, playerY, playerZ, fullRegen));
Thread thread = new Thread(() -> generateLodBuffersThread(renderer, lodDim, playerBlockPos, fullRegen));
mainGenThread.execute(thread);
}
@@ -205,17 +201,15 @@ 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,
int playerX, int playerY, int playerZ, boolean fullRegen)
AbstractBlockPosWrapper playerBlockPos, boolean fullRegen)
{
bufferLock.lock();
try
{
// round the player's block position down to the nearest chunk BlockPos
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);
AbstractChunkPosWrapper playerChunkPos = WRAPPER_FACTORY.createChunkPos(playerBlockPos);
AbstractBlockPosWrapper playerBlockPosRounded = playerChunkPos.getWorldPosition();
//long startTime = System.currentTimeMillis();
@@ -224,6 +218,11 @@ 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()];
@@ -237,15 +236,14 @@ public class LodBufferBuilderFactory
vertexOptimizerCache = new VertexOptimizer[lodDim.getWidth()][lodDim.getWidth()];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPosX = playerChunkX;
buildableCenterChunkPosZ = playerChunkZ;
buildableCenterChunkPos = playerChunkPos;
//================================//
// create the nodeToRenderThreads //
//================================//
skyLightPlayer = MC.getWrappedClientWorld().getSkyLight(playerX, playerY, playerZ);
skyLightPlayer = MC.getWrappedClientWorld().getSkyLight(playerBlockPos);
for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++)
{
@@ -297,7 +295,9 @@ public class LodBufferBuilderFactory
int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte) 0);
//we get or create the map that will contain the adj data
Map<LodDirection, long[]> adjData = ThreadMapUtil.getAdjDataArray(maxVerticalData);
Map<LodDirection, int[]> adjData = ThreadMapUtil.getAdjDataArray(maxVerticalData);
Map<LodDirection, byte[]> adjFlags = ThreadMapUtil.getAdjFlagsArray(maxVerticalData);
//previous setToRender cache
if (setsToRender[xR][zR] == null)
@@ -311,8 +311,8 @@ public class LodBufferBuilderFactory
lodDim.getPosToRender(
posToRender,
regionPos,
playerX,
playerZ);
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
@@ -330,14 +330,14 @@ public class LodBufferBuilderFactory
posX = posToRender.getNthPosX(index);
posZ = posToRender.getNthPosZ(index);
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkX;
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkZ;
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.getX();
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.getZ();
//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, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance))
if(isThisPositionGoingToBeRendered(detailLevel, posX, posZ, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance))
{
continue;
}
@@ -357,9 +357,11 @@ 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) - playerChunkX;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkZ;
int color;
int data;
byte flags;
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.getX();
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.getZ();
adjPosInPlayerChunk = (chunkXdist == 0 && chunkZdist == 0);
//If the adj block is rendered in the same region and with same detail
@@ -368,25 +370,29 @@ 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, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance)
&& !isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance)
&& !(posNotInPlayerChunk && adjPosInPlayerChunk))
{
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++)
{
data = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex);
flags = lodDim.getFlags(detailLevel, xAdj, zAdj, verticalIndex);
adjShadeDisabled[VertexOptimizer.DIRECTION_INDEX.get(lodDirection)] = false;
adjData.get(lodDirection)[verticalIndex] = data;
adjFlags.get(lodDirection)[verticalIndex] = flags;
}
}
else
{
//Otherwise, we check if this position is
data = lodDim.getSingleData(detailLevel, xAdj, zAdj);
data = lodDim.getData(detailLevel, xAdj, zAdj, 0);
flags = lodDim.getFlags(detailLevel, xAdj, zAdj, 0);
adjData.get(lodDirection)[0] = DataPointUtil.EMPTY_DATA;
adjData.get(lodDirection)[0] = 0;
adjFlags.get(lodDirection)[0] = 0;
if ((isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance) || (posNotInPlayerChunk && adjPosInPlayerChunk))
&& !DataPointUtil.isVoid(data))
if ((isThisPositionGoingToBeRendered(detailLevel, xAdj, zAdj, playerChunkPos, vanillaRenderedChunks, gameChunkRenderDistance) || (posNotInPlayerChunk && adjPosInPlayerChunk))
&& DataPointUtil.doesItExist(flags) && !DataPointUtil.isVoid(flags))
{
adjShadeDisabled[VertexOptimizer.DIRECTION_INDEX.get(lodDirection)] = DataPointUtil.getAlpha(data) < 255;
}
@@ -396,32 +402,47 @@ public class LodBufferBuilderFactory
// We render every vertical lod present in this position
// We only stop when we find a block that is void or non-existing block
long data;
int color;
int data;
byte flags;
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++)
{
//we get the above block as adj UP
if (verticalIndex > 0)
{
adjData.get(LodDirection.UP)[0] = lodDim.getData(detailLevel, posX, posZ, verticalIndex - 1);
adjFlags.get(LodDirection.UP)[0] = lodDim.getFlags(detailLevel, posX, posZ, verticalIndex - 1);
}
else
adjData.get(LodDirection.UP)[0] = DataPointUtil.EMPTY_DATA;
{
adjData.get(LodDirection.UP)[0] = 0;
adjFlags.get(LodDirection.UP)[0] = 0;
}
//we get the below block as adj DOWN
if (verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ) - 1)
{
adjData.get(LodDirection.DOWN)[0] = lodDim.getData(detailLevel, posX, posZ, verticalIndex + 1);
adjFlags.get(LodDirection.DOWN)[0] = lodDim.getFlags(detailLevel, posX, posZ, verticalIndex + 1);
}
else
adjData.get(LodDirection.DOWN)[0] = DataPointUtil.EMPTY_DATA;
{
adjData.get(LodDirection.DOWN)[0] = 0;
adjFlags.get(LodDirection.DOWN)[0] = 0;
}
//We extract the data to render
color = lodDim.getColor(detailLevel, posX, posZ, verticalIndex);
data = lodDim.getData(detailLevel, posX, posZ, verticalIndex);
flags = lodDim.getFlags(detailLevel, posX, posZ, verticalIndex);
//If the data is not renderable (Void or non-existing) we stop since there is no data left in this position
if (DataPointUtil.isVoid(data) || !DataPointUtil.doesItExist(data))
if (!DataPointUtil.doesItExist(flags) || DataPointUtil.isVoid(flags))
break;
//We send the call to create the vertices
LodTemplate.CUBIC.template.addLodToBuffer(currentBuffers[bufferIndex], playerX, playerY, playerZ, data, adjData,
CONFIG.client().graphics().advancedGraphics().getLodTemplate().template.addLodToBuffer(currentBuffers[bufferIndex], playerBlockPosRounded, color, data, flags, adjData, adjFlags,
detailLevel, posX, posZ, vertexOptimizer, renderer.previousDebugMode, adjShadeDisabled);
}
@@ -429,9 +450,7 @@ public class LodBufferBuilderFactory
// the thread executed successfully
return true;
};
nodeToRenderThreads.add(dataToRenderThread);
}
} // region z
} // region z
@@ -491,12 +510,12 @@ public class LodBufferBuilderFactory
}
}
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, int chunkPosX, int chunkPosZ, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, AbstractChunkPosWrapper playerChunkPos, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
// skip any chunks that Minecraft is going to render
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - chunkPosX;
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - chunkPosZ;
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.getX();
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.getZ();
// check if the chunk is on the border
boolean isItBorderPos;
@@ -566,7 +585,7 @@ public class LodBufferBuilderFactory
{
regionMemoryRequired = DEFAULT_MEMORY_ALLOCATION;
// if the memory required is greater than the max buffer
// if the memory required is greater than the max buffer
// capacity, divide the memory across multiple buffers
if (regionMemoryRequired > LodUtil.MAX_ALLOCATABLE_DIRECT_MEMORY)
{
@@ -631,7 +650,7 @@ public class LodBufferBuilderFactory
drawableStorageBufferIds[x][z][i] = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableStorageBufferIds[x][z][i]);
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
}
}
@@ -882,7 +901,7 @@ public class LodBufferBuilderFactory
if (vbo.id != -1 && GLProxy.getInstance().getGlContext() == GLProxyContext.LOD_BUILDER)
{
// this is how many points will be rendered
vbo.vertexCount = (uploadBuffer.capacity() / ((Float.BYTES * 3) + (Byte.BYTES * 4) + Byte.BYTES + Byte.BYTES)); // TODO make this change with the LodTemplate
vbo.vertexCount = (uploadBuffer.capacity() / ((Float.BYTES * 3) + (Byte.BYTES * 4))); // TODO make this change with the LodTemplate
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id);
try
@@ -1019,8 +1038,7 @@ public class LodBufferBuilderFactory
drawableStorageBufferIds = buildableStorageBufferIds;
buildableStorageBufferIds = tmpStorage;
drawableCenterChunkPosX = buildableCenterChunkPosX;
drawableCenterChunkPosZ = buildableCenterChunkPosZ;
drawableCenterChunkPos = buildableCenterChunkPos;
// the vbos have been swapped
switchVbos = false;
@@ -1036,7 +1054,7 @@ public class LodBufferBuilderFactory
}
}
return new VertexBuffersAndOffset(drawableVbos, drawableStorageBufferIds, drawableCenterChunkPosX, drawableCenterChunkPosZ);
return new VertexBuffersAndOffset(drawableVbos, drawableStorageBufferIds, drawableCenterChunkPos);
}
/** A simple container to pass multiple objects back in the getVertexBuffers method. */
@@ -1044,15 +1062,13 @@ public class LodBufferBuilderFactory
{
public final LodVertexBuffer[][][] vbos;
public final int[][][] storageBufferIds;
public int drawableCenterChunkPosX;
public int drawableCenterChunkPosZ;
public final AbstractChunkPosWrapper drawableCenterChunkPos;
public VertexBuffersAndOffset(LodVertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, int newDrawableCenterChunkPosX, int newDrawableCenterChunkPosZ)
public VertexBuffersAndOffset(LodVertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, AbstractChunkPosWrapper newDrawableCenterChunkPos)
{
vbos = newVbos;
storageBufferIds = newStorageBufferIds;
drawableCenterChunkPosX = newDrawableCenterChunkPosX;
drawableCenterChunkPosZ = newDrawableCenterChunkPosZ;
drawableCenterChunkPos = newDrawableCenterChunkPos;
}
}
@@ -32,24 +32,21 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
* This is the abstract class used to create different
* BufferBuilders.
* @author James Seibel
* @version 12-8-2021
* @version 11-13-2021
*/
public abstract class AbstractLodTemplate
{
/** Uploads the given LOD to the buffer. */
public abstract void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
public abstract void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags, Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled);
/** add the given position and color to the buffer */
protected void addPosAndColor(LodBufferBuilder buffer,
float x, float y, float z,
int color, byte skyLightValue, byte blockLightValue)
int color)
{
// TODO re-add transparency by replacing the color 255 with "ColorUtil.getAlpha(color)"
buffer.position(x, y, z)
.color(ColorUtil.getRed(color), ColorUtil.getGreen(color), ColorUtil.getBlue(color), 255)
.minecraftLightValue(skyLightValue).minecraftLightValue(blockLightValue)
.endVertex();
// TODO re-add transparency by replacing the 255 with "ColorUtil.getAlpha(color)"
buffer.vertex(x, y, z).color(ColorUtil.getRed(color), ColorUtil.getGreen(color), ColorUtil.getBlue(color), 255).endVertex();
}
}
@@ -25,13 +25,15 @@ import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.objects.VertexOptimizer;
import com.seibel.lod.core.objects.opengl.LodBufferBuilder;
import com.seibel.lod.core.util.ColorUtil;
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.
* @author James Seibel
* @version 12-8-2021
* @version 11-8-2021
*/
public class CubicLodTemplate extends AbstractLodTemplate
{
@@ -42,7 +44,9 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
@Override
public void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos,
int color, int data, byte flags,
Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
if (vertexOptimizer == null)
@@ -51,12 +55,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
// equivalent to 2^detailLevel
int blockWidth = 1 << detailLevel;
int color;
if (debugging != DebugMode.OFF)
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
else
color = DataPointUtil.getColor(data);
generateBoundingBox(
vertexOptimizer,
@@ -64,12 +64,11 @@ public class CubicLodTemplate extends AbstractLodTemplate
DataPointUtil.getDepth(data),
blockWidth,
posX * blockWidth, 0, posZ * blockWidth, // x, y, z offset
playerX,
playerY,
playerZ,
bufferCenterBlockPos,
adjData,
adjFlags,
color,
DataPointUtil.getLightSkyAlt(data),
DataPointUtil.getLightSkyAlt(data, flags),
DataPointUtil.getLightBlock(data),
adjShadeDisabled);
@@ -79,9 +78,12 @@ public class CubicLodTemplate extends AbstractLodTemplate
private void generateBoundingBox(VertexOptimizer vertexOptimizer,
int height, int depth, int width,
double xOffset, double yOffset, double zOffset,
int playerX, int playerY, int playerZ,
Map<LodDirection, long[]> adjData,
int color, byte skyLight, byte blockLight,
AbstractBlockPosWrapper bufferCenterBlockPos,
Map<LodDirection, int[]> adjData,
Map<LodDirection, byte[]> adjFlags,
int color,
int skyLight,
int blockLight,
boolean[] adjShadeDisabled)
{
// don't add an LOD if it is empty
@@ -96,36 +98,41 @@ 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 = -playerX;
double z = -playerZ;
double x = -bufferCenterBlockPos.getX();
double z = -bufferCenterBlockPos.getZ();
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.setAdjData(adjData);
vertexOptimizer.setUpCulling(32, bufferCenterBlockPos);
vertexOptimizer.setAdjData(adjData, adjFlags);
}
private void addBoundingBoxToBuffer(LodBufferBuilder buffer, VertexOptimizer vertexOptimizer)
{
int color;
byte skyLight;
byte blockLight;
int skyLight;
int blockLight;
for (LodDirection lodDirection : VertexOptimizer.DIRECTIONS)
{
if(vertexOptimizer.isCulled(lodDirection))
continue;
int verticalFaceIndex = 0;
while (vertexOptimizer.shouldRenderFace(lodDirection, verticalFaceIndex))
{
for (int vertexIndex = 0; vertexIndex < 6; vertexIndex++)
{
skyLight = vertexOptimizer.getSkyLight(lodDirection, verticalFaceIndex);
blockLight = (byte) vertexOptimizer.getBlockLight();
color = vertexOptimizer.getColor(lodDirection);
skyLight = vertexOptimizer.getSkyLight(lodDirection, verticalFaceIndex);
blockLight = vertexOptimizer.getBlockLight();
color = ColorUtil.applyLightValue(color, skyLight, blockLight);
addPosAndColor(buffer,
vertexOptimizer.getX(lodDirection, vertexIndex),
vertexOptimizer.getY(lodDirection, vertexIndex, verticalFaceIndex) + DataPointUtil.VERTICAL_OFFSET,
vertexOptimizer.getZ(lodDirection, vertexIndex),
color, skyLight, blockLight );
color);
}
verticalFaceIndex++;
}
@@ -39,7 +39,8 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public class DynamicLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags,
Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
@@ -37,7 +37,8 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
public class TriangularLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(LodBufferBuilder buffer, int playerX, int playerY, int playerZ, long data, Map<LodDirection, long[]> adjData,
public void addLodToBuffer(LodBufferBuilder buffer, AbstractBlockPosWrapper bufferCenterBlockPos, int color, int data, byte flags,
Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags,
byte detailLevel, int posX, int posZ, VertexOptimizer vertexOptimizer, DebugMode debugging, boolean[] adjShadeDisabled)
{
ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
@@ -162,7 +162,6 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config)
throws IllegalArgumentException
{
//long executeTime = System.currentTimeMillis();
if (chunk == null)
throw new IllegalArgumentException("generateLodFromChunk given a null chunk");
@@ -170,7 +169,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
int startZ;
LodRegion region = lodDim.getRegion(chunk.getRegionPosX(), chunk.getRegionPosZ());
LodRegion region = lodDim.getRegion(chunk.getPos().getRegionX(), chunk.getPos().getRegionZ());
if (region == null)
return;
@@ -196,104 +195,119 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
startX = detail.startX[i];
startZ = detail.startZ[i];
long[] data;
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ);
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.getChunkPosX(), chunk.getChunkPosZ());
//executeTime = System.currentTimeMillis() - executeTime;
//if (executeTime > 0) ClientApi.LOGGER.info("generateLodNodeFromChunk level: " + detailLevel + " time ms: " + executeTime);
}
/** creates a vertical DataPoint */
private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunkWrapper chunk, LodBuilderConfig config, int startX, int startZ)
{
// equivalent to 2^detailLevel
int size = 1 << detail.detailLevel;
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail.detailLevel);
int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
int height;
int depth;
int color;
int light;
int lightSky;
int lightBlock;
int generation = config.distanceGenerationMode.complexity;
int xRel;
int zRel;
int xAbs;
int yAbs;
int zAbs;
boolean hasCeiling = MC.getWrappedClientWorld().getDimensionType().hasCeiling();
boolean hasSkyLight = MC.getWrappedClientWorld().getDimensionType().hasSkyLight();
boolean isDefault;
int index;
for (index = 0; index < size * size; index++)
{
xRel = startX + index % size;
zRel = startZ + index / size;
xAbs = chunk.getMinX() + xRel;
zAbs = chunk.getMinZ() + zRel;
// creates a vertical DataPoint
// equivalent to 2^detailLevel
int size = 1 << detail.detailLevel;
//Calculate the height of the lod
yAbs = chunk.getMaxY(xRel, zRel); //DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET + 1;
int count = 0;
boolean topBlock = true;
while (yAbs > 0)
int[] dataToMergeColor = ThreadMapUtil.getBuilderVerticalArrayColor(detail.detailLevel);
int[] dataToMergeData = ThreadMapUtil.getBuilderVerticalArrayData(detail.detailLevel);
byte[] dataToMergeFlags = ThreadMapUtil.getBuilderVerticalArrayFlags(detail.detailLevel);
int verticalData = DataPointUtil.WORLD_HEIGHT / 2 + 1;
AbstractChunkPosWrapper chunkPos = chunk.getPos();
int height;
int depth;
int color;
int light;
int lightSky;
int lightBlock;
byte generation = config.distanceGenerationMode.complexity;
int xRel;
int zRel;
int xAbs;
int yAbs;
int zAbs;
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++)
{
height = determineHeightPointFrom(chunk, config, xAbs, yAbs, zAbs);
xRel = startX + index % size;
zRel = startZ + index / size;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
// If the lod is at the default height, it must be void data
if (height == DEFAULT_HEIGHT)
//Calculate the height of the lod
yAbs = DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET + 1;
int count = 0;
boolean topBlock = true;
while (yAbs > 0)
{
if (topBlock)
dataToMerge[index * verticalData] = DataPointUtil.createVoidDataPoint(generation);
break;
height = determineHeightPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
// If the lod is at the default height, it must be void data
if (height == DEFAULT_HEIGHT)
{
if (topBlock)
dataToMergeFlags[index * verticalData] = DataPointUtil.createVoidDataPoint(generation);
break;
}
yAbs = height - 1;
// We search light on above air block
depth = determineBottomPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
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);
}
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);
}
lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111;
isDefault = ((light >> 8)) == 1;
DataPointUtil.createDataPoint(height - DataPointUtil.VERTICAL_OFFSET, depth - DataPointUtil.VERTICAL_OFFSET, color, lightSky, lightBlock, generation, isDefault);
dataToMergeColor[index * verticalData + count] = ThreadMapUtil.dataPointColor;
dataToMergeData[index * verticalData + count] = ThreadMapUtil.dataPointData;
dataToMergeFlags[index * verticalData + count] = ThreadMapUtil.dataPointFlags;
topBlock = false;
yAbs = depth - 1;
count++;
}
yAbs = height - 1;
// We search light on above air block
depth = determineBottomPointFrom(chunk, config, xAbs, yAbs, zAbs);
if (hasCeiling && topBlock)
{
yAbs = depth;
light = getLightValue(chunk, xAbs,yAbs,zAbs, true, hasSkyLight, true);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs);
}
else
{
light = getLightValue(chunk, xAbs, yAbs, zAbs, hasCeiling, hasSkyLight, topBlock);
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs);
}
lightBlock = light & 0b1111;
lightSky = (light >> 4) & 0b1111;
isDefault = ((light >> 8)) == 1;
dataToMerge[index * verticalData + count] = DataPointUtil.createDataPoint(height - DataPointUtil.VERTICAL_OFFSET, depth - DataPointUtil.VERTICAL_OFFSET, color, lightSky, lightBlock, generation, isDefault);
topBlock = false;
yAbs = depth - 1;
count++;
}
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
int[] mergedColor = ThreadMapUtil.getRawVerticalDataArrayColor();
int[] mergedData = ThreadMapUtil.getRawVerticalDataArrayData();
byte[] mergedFlags = ThreadMapUtil.getRawVerticalDataArrayFlags();
//lodDim.clear(detailLevel, posX, posZ);
if (mergedFlags.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, mergedColor, mergedData, mergedFlags, false);
}
}
return dataToMerge;
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().getX(), chunk.getPos().getZ());
}
/**
* 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)
private short determineBottomPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, AbstractBlockPosWrapper blockPos)
{
short depth = DEFAULT_DEPTH;
for (int y = yAbs; y >= 0; y--)
{
if (!isLayerValidLodPoint(chunk, xAbs, y, zAbs))
blockPos.set(xAbs, y, zAbs);
if (!isLayerValidLodPoint(chunk, blockPos))
{
depth = (short) (y + 1);
break;
@@ -303,9 +317,8 @@ 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)
private short determineHeightPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, AbstractBlockPosWrapper blockPos)
{
short height = DEFAULT_HEIGHT;
if (config.useHeightmap)
height = (short) chunk.getHeightMapValue(xAbs, zAbs);
@@ -313,7 +326,8 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
{
for (int y = yAbs; y >= 0; y--)
{
if (isLayerValidLodPoint(chunk, xAbs, y, zAbs))
blockPos.set(xAbs, y, zAbs);
if (isLayerValidLodPoint(chunk, blockPos))
{
height = (short) (y + 1);
break;
@@ -333,18 +347,19 @@ 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 x, int y, int z)
private int generateLodColor(IChunkWrapper chunk, LodBuilderConfig builderConfig, int xRel, int yAbs, int zRel, AbstractBlockPosWrapper blockPos)
{
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(x, y, z).getColorForBiome(x, z);
colorInt = chunk.getBiome(xRel, yAbs, zRel).getColorForBiome(xRel, zRel);
}
else
{
colorInt = getColorForBlock(chunk, x, y, z);
blockPos.set(chunk.getPos().getMinBlockX() + xRel, yAbs, chunk.getPos().getMinBlockZ() + zRel);
colorInt = getColorForBlock(chunk, blockPos);
// 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
@@ -352,7 +367,8 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
int aboveColorInt = 0;
if (config.client().worldGenerator().getBlocksToAvoid().nonFull || config.client().worldGenerator().getBlocksToAvoid().noCollision)
{
aboveColorInt = getColorForBlock(chunk, x, y, z);
blockPos.set(chunk.getPos().getMinBlockX() + xRel, yAbs + 1, chunk.getPos().getMinBlockZ() + zRel);
aboveColorInt = getColorForBlock(chunk, blockPos);
}
//if (colorInt == 0 && yAbs > 0)
@@ -369,7 +385,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
}
/** Gets the light value for the given block position */
private int getLightValue(IChunkWrapper chunk, int x, int y, int z, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
private int getLightValue(IChunkWrapper chunk, AbstractBlockPosWrapper blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
{
int skyLight = 0;
int blockLight;
@@ -378,25 +394,25 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
IWorldWrapper world = MC.getWrappedServerWorld();
int blockBrightness = chunk.getEmittedBrightness(x, y, z);
int blockBrightness = chunk.getEmittedBrightness(blockPos);
// get the air block above or below this block
if (hasCeiling && topBlock)
y--;
blockPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
else
y++;
blockPos.set(blockPos.getX(), blockPos.getY() + 1, blockPos.getZ());
if (world != null)
{
// server world sky light (always accurate)
blockLight = world.getBlockLight(x,y,z);
blockLight = world.getBlockLight(blockPos);
if (topBlock && !hasCeiling && hasSkyLight)
skyLight = DEFAULT_MAX_LIGHT;
else
{
if (hasSkyLight)
skyLight = world.getSkyLight(x,y,z);
skyLight = world.getSkyLight(blockPos);
//else
// skyLight = 0;
}
@@ -404,7 +420,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 (y >= MC.getWrappedClientWorld().getSeaLevel() - 5)
if (blockPos.getY() >= MC.getWrappedClientWorld().getSeaLevel() - 5)
{
skyLight = 12;
isDefault = 1;
@@ -425,7 +441,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
else
{
// client world sky light (almost never accurate)
blockLight = world.getBlockLight(x,y,z);
blockLight = world.getBlockLight(blockPos);
// estimate what the lighting should be
if (hasSkyLight || !hasCeiling)
{
@@ -434,14 +450,14 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
else
{
if (hasSkyLight)
skyLight = world.getSkyLight(x,y,z);
skyLight = world.getSkyLight(blockPos);
//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 (y >= MC.getWrappedClientWorld().getSeaLevel() - 5)
if (blockPos.getY() >= MC.getWrappedClientWorld().getSeaLevel() - 5)
{
skyLight = 12;
isDefault = 1;
@@ -460,19 +476,24 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
}
/** Returns a color int for the given block. */
private int getColorForBlock(IChunkWrapper chunk, int x, int y, int z)
private int getColorForBlock(IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
{
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(x, y, z);
IBlockShapeWrapper blockShapeWrapper = chunk.getBlockShapeWrapper(blockPos);
if (chunk.isWaterLogged(x, y, z))
if (chunk.isWaterLogged(blockPos))
blockColorWrapper = BLOCK_COLOR.getWaterColor();
else
blockColorWrapper = chunk.getBlockColorWrapper(x, y, z);
blockColorWrapper = chunk.getBlockColorWrapper(blockPos);
if (blockShapeWrapper.isToAvoid())
return 0;
@@ -482,7 +503,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
if (blockColorWrapper.hasTint())
{
IBiomeWrapper biome = chunk.getBiome(x, y, z);
IBiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
int tintValue;
if (blockColorWrapper.hasGrassTint())
// grass and green plants
@@ -502,15 +523,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, int x, int y, int z)
private boolean isLayerValidLodPoint(IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
{
if (chunk.isWaterLogged(x, y, z))
if (chunk.isWaterLogged(blockPos))
return true;
boolean nonFullAvoidance = config.client().worldGenerator().getBlocksToAvoid().nonFull;
boolean noCollisionAvoidance = config.client().worldGenerator().getBlocksToAvoid().noCollision;
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(x, y, z);
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(blockPos);
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,502 +1,5 @@
package com.seibel.lod.core.dataFormat;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.ThreadMapUtil;
import static com.seibel.lod.core.builders.bufferBuilding.LodBufferBuilderFactory.skyLightPlayer;
public class BlockDataFormat
{
/*
|a |a |a |a |r |r |r |r |
|r |r |r |r |g |g |g |g |
|g |g |g |g |b |b |b |b |
|b |b |b |b |h |h |h |h |
|h |h |h |h |h |h |d |d |
|d |d |d |d |d |d |d |d |
|bl |bl |bl |bl |sl |sl |sl |sl |
|l |l |f |g |g |g |v |e |
*/
// Reminder: bytes have range of [-128, 127].
// When converting to or from an int a 128 should be added or removed.
// If there is a bug with color then it's probably caused by this.
//To be used in the future for negative value
//public final static int MIN_DEPTH = -64;
//public final static int MIN_HEIGHT = -64;
public final static int EMPTY_DATA = 0;
public static final short VERTICAL_OFFSET = -64;
public static int WORLD_HEIGHT = 1024;
public final static int ALPHA_DOWNSIZE_SHIFT = 4;
//public final static int BLUE_COLOR_SHIFT = 0;
//public final static int GREEN_COLOR_SHIFT = 8;
//public final static int RED_COLOR_SHIFT = 16;
//public final static int ALPHA_COLOR_SHIFT = 24;
public final static int BLUE_SHIFT = 36;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24;
public final static int COLOR_SHIFT = 36;
public final static int HEIGHT_SHIFT = 26;
public final static int DEPTH_SHIFT = 16;
public final static int BLOCK_LIGHT_SHIFT = 12;
public final static int SKY_LIGHT_SHIFT = 8;
//public final static int LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
//public final static int VERTICAL_INDEX_SHIFT = 6;
public final static int FLAG_SHIFT = 5;
public final static int GEN_TYPE_SHIFT = 2;
public final static int VOID_SHIFT = 1;
public final static int EXISTENCE_SHIFT = 0;
public final static long ALPHA_MASK = 0b1111;
public final static long RED_MASK = 0b1111_1111;
public final static long GREEN_MASK = 0b1111_1111;
public final static long BLUE_MASK = 0b1111_1111;
public final static long COLOR_MASK = 0b11111111_11111111_11111111;
public final static long HEIGHT_MASK = 0b11_1111_1111;
public final static long DEPTH_MASK = 0b11_1111_1111;
//public final static long LIGHTS_MASK = 0b1111_1111;
public final static long BLOCK_LIGHT_MASK = 0b1111;
public final static long SKY_LIGHT_MASK = 0b1111;
//public final static long VERTICAL_INDEX_MASK = 0b11;
public final static long FLAG_MASK = 0b1;
public final static long GEN_TYPE_MASK = 0b111;
public final static long VOID_MASK = 1;
public final static long EXISTENCE_MASK = 1;
public static long createVoidDataPoint(int generationMode)
{
long dataPoint = 0;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
dataPoint += VOID_MASK << VOID_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
}
public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode, boolean flag)
{
return createDataPoint(
ColorUtil.getAlpha(color),
ColorUtil.getRed(color),
ColorUtil.getGreen(color),
ColorUtil.getBlue(color),
height, depth, lightSky, lightBlock, generationMode, flag);
}
public static long createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode, boolean flag)
{
long dataPoint = 0;
dataPoint += (long) (alpha >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT;
dataPoint += (red & RED_MASK) << RED_SHIFT;
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT;
dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT;
dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT;
dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT;
dataPoint += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
dataPoint += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
if (flag)
dataPoint += FLAG_MASK << FLAG_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
}
public static short getHeight(long dataPoint)
{
return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(long dataPoint)
{
return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getAlpha(long dataPoint)
{
return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111);
}
public static short getRed(long dataPoint)
{
return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
{
return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
{
return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK);
}
public static byte getLightSky(long dataPoint)
{
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightSkyAlt(long dataPoint)
{
if (skyLightPlayer == 0 && ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1)
return 0;
else
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightBlock(long dataPoint)
{
return (byte) ((dataPoint >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
public static boolean getFlag(long dataPoint)
{
return ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1;
}
public static byte getGenerationMode(long dataPoint)
{
return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
}
public static boolean isVoid(long dataPoint)
{
return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1);
}
public static boolean doesItExist(long dataPoint)
{
return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
}
public static int getColor(long dataPoint)
{
return (int) (((dataPoint >>> COLOR_SHIFT) & COLOR_MASK) | (/*((dataPoint >>> (ALPHA_SHIFT - ALPHA_DOWNSIZE_SHIFT)) | 0b1111)*/255 << 24));
}
/** This is used to convert a dataPoint to string (useful for the print function) */
@SuppressWarnings("unused")
public static String toString(long dataPoint)
{
return getHeight(dataPoint) + " " +
getDepth(dataPoint) + " " +
getAlpha(dataPoint) + " " +
getRed(dataPoint) + " " +
getBlue(dataPoint) + " " +
getGreen(dataPoint) + " " +
getLightBlock(dataPoint) + " " +
getLightSky(dataPoint) + " " +
getGenerationMode(dataPoint) + " " +
isVoid(dataPoint) + " " +
doesItExist(dataPoint) + '\n';
}
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;
}
}
/**
* This method merge column of multiple data together
* @param dataToMerge one or more columns of data
* @param inputVerticalData vertical size of an input data
* @param maxVerticalData max vertical size of the merged data
* @return one column of correctly parsed data
*/
public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData)
{
int size = dataToMerge.length / inputVerticalData;
// We initialize the arrays that are going to be used
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((WORLD_HEIGHT / 2 + 1) * 2);
long[] dataPoint = ThreadMapUtil.getVerticalDataArray(DetailDistanceUtil.getMaxVerticalData(0));
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 (doesItExist(singleData))
{
genMode = Math.min(genMode, getGenerationMode(singleData));
allEmpty = false;
if (!isVoid(singleData))
{
allVoid = false;
depth = getDepth(singleData);
height = 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 dataPoint;
if (allVoid)
{
dataPoint[0] = createVoidDataPoint(genMode);
return dataPoint;
}
//we limit the vertical portion to maxVerticalData
int j = 0;
while (count > maxVerticalData)
{
ii = WORLD_HEIGHT - 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--)
{
height = heightAndDepth[j * 2];
depth = heightAndDepth[j * 2 + 1];
if ((depth == 0 && height == 0) || j >= heightAndDepth.length / 2)
break;
int numberOfChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempLightBlock = 0;
int tempLightSky = 0;
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 (doesItExist(singleData) && !isVoid(singleData))
{
if ((depth <= getDepth(singleData) && getDepth(singleData) <= height)
|| (depth <= getHeight(singleData) && getHeight(singleData) <= height))
{
if (getHeight(singleData) > getHeight(data))
data = singleData;
}
}
else
break;
}
if (!doesItExist(data))
{
singleData = dataToMerge[index * inputVerticalData];
data = createVoidDataPoint(getGenerationMode(singleData));
}
if (doesItExist(data))
{
allEmpty = false;
if (!isVoid(data))
{
numberOfChildren++;
allVoid = false;
tempAlpha += getAlpha(data);
tempRed += getRed(data);
tempGreen += getGreen(data);
tempBlue += getBlue(data);
tempLightBlock += getLightBlock(data);
tempLightSky += getLightSky(data);
if (!getFlag(data))
allDefault = false;
}
tempGenMode = (byte) Math.min(tempGenMode, getGenerationMode(data));
}
else
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
}
if (allEmpty)
//no child has been initialized
dataPoint[j] = EMPTY_DATA;
else if (allVoid)
//all the children are void
dataPoint[j] = 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;
dataPoint[j] = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
}
}
return dataPoint;
}
}
@@ -2,13 +2,4 @@ package com.seibel.lod.core.dataFormat;
public class ColorFormat
{
public final static int BLUE_SHIFT = 0;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24;
public final static long ALPHA_MASK = 0b1111;
public final static long RED_MASK = 0b1111_1111;
public final static long GREEN_MASK = 0b1111_1111;
public final static long BLUE_MASK = 0b1111_1111;
}
@@ -0,0 +1,5 @@
package com.seibel.lod.core.dataFormat;
public class DepthHeightFormat
{
}
@@ -2,38 +2,4 @@ package com.seibel.lod.core.dataFormat;
public class LightFormat
{
public final static byte INT_BLOCK_LIGHT_SHIFT = 16;
public final static byte INT_SKY_LIGHT_SHIFT = 0;
public final static byte BYTE_BLOCK_LIGHT_SHIFT = 4;
public final static byte BYTE_SKY_LIGHT_SHIFT = 0;
public final static byte BLOCK_LIGHT_MASK = 0b1111;
public final static byte SKY_LIGHT_MASK = 0b1111;
public byte formatLightAsByte(byte skyLight, byte blockLight)
{
return (byte) (((skyLight & SKY_LIGHT_MASK) << BYTE_SKY_LIGHT_SHIFT) | ((blockLight & BLOCK_LIGHT_MASK) << BYTE_BLOCK_LIGHT_SHIFT));
}
public int formatLightAsInt(byte skyLight, byte blockLight)
{
return ((skyLight & SKY_LIGHT_MASK) << INT_SKY_LIGHT_SHIFT) | ((blockLight & BLOCK_LIGHT_MASK) << INT_BLOCK_LIGHT_SHIFT);
}
public int convertByteToIntFormat(byte lights)
{
return 0;
}
public byte getSkyLight(byte lights)
{
return (byte) ((lights >>> BYTE_SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public byte getBlockLight(byte lights)
{
return (byte) ((lights >>> BYTE_BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
}
@@ -2,77 +2,4 @@ package com.seibel.lod.core.dataFormat;
public class PositionDataFormat
{
public final static byte LOD_COUNT_SHIFT = 6;
public final static byte CORRECT_LIGHT_SHIFT = 5;
public final static byte GEN_TYPE_SHIFT = 2;
public final static byte VOID_SHIFT = 1;
public final static byte EXISTENCE_SHIFT = 0;
//We are able to count up to 64 different lods in a column
public final static short LOD_COUNT_MASK = 0b11_1111;
public final static short CORRECT_LIGHT_MASK = 0b1;
public final static short GEN_TYPE_MASK = 0b111;
public final static short VOID_MASK = 0b1;
public final static short EXISTENCE_MASK = 0b1;
public final static int EMPTY_DATA = 0;
public final static int VOID_DATA = VOID_MASK<<VOID_SHIFT + EXISTENCE_MASK<<EXISTENCE_SHIFT;
public static short createVoidPositionData(byte generationMode)
{
short positionData = 0;
positionData |= (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
positionData |= VOID_MASK << VOID_SHIFT;
positionData |= EXISTENCE_MASK << EXISTENCE_SHIFT;
return positionData;
}
public static short createPositionData(int lodCount, boolean correctLight, byte generationMode)
{
short positionData = 0;
positionData |= (lodCount & LOD_COUNT_MASK) << LOD_COUNT_SHIFT;
positionData |= (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
if (correctLight)
positionData |= CORRECT_LIGHT_MASK << CORRECT_LIGHT_SHIFT;
positionData |= EXISTENCE_MASK << EXISTENCE_SHIFT;
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 getLightFlag(short dataPoint)
{
return ((dataPoint >>> CORRECT_LIGHT_SHIFT) & CORRECT_LIGHT_MASK) == 1;
}
public static byte getGenerationMode(short dataPoint)
{
return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
}
public static boolean isVoid(short dataPoint)
{
return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1);
}
public static boolean doesItExist(short dataPoint)
{
return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
}
}
@@ -1,81 +0,0 @@
package com.seibel.lod.core.dataFormat;
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;
public final static byte LEVEL_SHIFT = 3;
public final static byte BOTTOM_TYPE_SHIFT = 2;
public final static byte TRANSPARENCY_SHIFT = 1;
public final static byte EMPTY_LOD_SHIFT = 0;
public final static int HEIGHT_MASK = 0b1111_1111_1111;
public final static int DEPTH_MASK = 0b1111_1111_1111;
public final static int LEVEL_MASK = 0b111;
public final static int TRANSPARENCY_MASK = 0b1;
public final static int BOTTOM_TYPE_MASK = 0b1;
public final static int EMPTY_LOD_MASK = 0b1;
public final static int EMPTY_LOD = 0;
public static int createVerticalData(int height, int depth, int level, boolean transparent, boolean bottom)
{
int verticalData = 0;
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;
if (transparent)
verticalData |= TRANSPARENCY_MASK << TRANSPARENCY_SHIFT;
verticalData |= EMPTY_LOD_MASK << EMPTY_LOD_SHIFT;
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) + MIN_WORLD_HEIGHT);
}
public static short getDepth(int verticalData)
{
return (short) (((verticalData >>> DEPTH_SHIFT) & DEPTH_MASK) + MIN_WORLD_HEIGHT);
}
public static byte getLevel(int verticalData)
{
return (byte) ((verticalData >>> LEVEL_SHIFT) & LEVEL_MASK);
}
public static boolean isTransparent(int verticalData)
{
return ((verticalData >>> TRANSPARENCY_SHIFT) & TRANSPARENCY_MASK) == 1;
}
public static boolean isBottom(int verticalData)
{
return ((verticalData >>> BOTTOM_TYPE_SHIFT) & BOTTOM_TYPE_MASK) == 1;
}
public static boolean doesItExist(int verticalData)
{
return (((verticalData >>> EMPTY_LOD_SHIFT) & EMPTY_LOD_MASK) == 1);
}
}
@@ -21,7 +21,6 @@ package com.seibel.lod.core.handlers;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
@@ -78,7 +77,7 @@ public class LodDimensionFileHandler
* file handler, older versions (smaller numbers) will be deleted and overwritten,
* newer versions (larger numbers) will be ignored and won't be read.
*/
public static final int LOD_SAVE_FILE_VERSION = 7;
public static final int LOD_SAVE_FILE_VERSION = 8;
/**
* Allow saving asynchronously, but never try to save multiple regions
@@ -208,14 +207,14 @@ public class LodDimensionFileHandler
break;
}
else if (fileVersion == 6)
else if (fileVersion < LOD_SAVE_FILE_VERSION)
{
//this is old, but readable version
byte[] data = ThreadMapUtil.getSaveContainer(tempDetailLevel);
inputStream.read(data);
inputStream.close();
// add the data to our region
region.addLevelContainer(new VerticalLevelContainer(data, 6));
region.addLevelContainer(new VerticalLevelContainer(data, fileVersion));
} else
{
// this file is a readable version,
@@ -1,104 +0,0 @@
package com.seibel.lod.core.objects;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class BlockBiomeCouple
{
public static ConcurrentMap<IBlockColorWrapper, BlockBiomeCouple> noBiomeIstanceCache = new ConcurrentHashMap<>();
public static ConcurrentMap<IBiomeWrapper, ConcurrentMap<IBlockColorWrapper, BlockBiomeCouple>> withBiomeIstanceCache = new ConcurrentHashMap<>();
String blockName;
String biomeName;
String coupleName;
IBiomeWrapper biomeColor;
IBlockColorWrapper blockColor;
public static void addBlockBiomeToCache(IBlockColorWrapper blockColor){
}
public static BlockBiomeCouple getBlockBiomeCouple(IBlockColorWrapper blockColor){
if(noBiomeIstanceCache.containsKey(blockColor))
{
return noBiomeIstanceCache.get(blockColor);
}
else
{
BlockBiomeCouple couple = new BlockBiomeCouple(blockColor);
noBiomeIstanceCache.put(blockColor,couple);
return couple;
}
}
public static BlockBiomeCouple getBlockBiomeCouple(IBiomeWrapper biomeColor, IBlockColorWrapper blockColor){
if(biomeColor == null)
{
return getBlockBiomeCouple(blockColor);
}
else
{
if(withBiomeIstanceCache.containsKey(biomeColor))
{
withBiomeIstanceCache.put(biomeColor, new ConcurrentHashMap<>());
}
ConcurrentMap<IBlockColorWrapper, BlockBiomeCouple> blockToCoupleMap = withBiomeIstanceCache.get(biomeColor);
if(blockToCoupleMap.containsKey(blockColor))
{
return blockToCoupleMap.get(blockColor);
}
else
{
BlockBiomeCouple couple = new BlockBiomeCouple(blockColor,biomeColor);
blockToCoupleMap.put(blockColor,couple);
return couple;
}
}
}
public BlockBiomeCouple(IBlockColorWrapper blockColor)
{
this.biomeColor = null;
this.blockColor = blockColor;
biomeName = "";
blockName = blockColor.getName();
coupleName = blockName;
}
public BlockBiomeCouple(IBlockColorWrapper blockColor, IBiomeWrapper biomeColor)
{
this.biomeColor = biomeColor;
this.blockColor = blockColor;
if(biomeColor == null)
biomeName = biomeColor.getName();
else
biomeName = "";
blockName = blockColor.getName();
coupleName = blockName + biomeName;
}
@Override public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof BlockBiomeCouple))
return false;
BlockBiomeCouple that = (BlockBiomeCouple) o;
return Objects.equals(blockName, that.blockName) && Objects.equals(biomeName, that.biomeName);
}
@Override public int hashCode()
{
return Objects.hash(blockName, biomeName);
}
}
@@ -200,6 +200,8 @@ 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 */
@@ -233,6 +235,8 @@ 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 */
@@ -305,37 +309,68 @@ 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
*/
public void setAdjData(Map<LodDirection, long[]> adjData)
public void setAdjData(Map<LodDirection, int[]> adjData, Map<LodDirection, byte[]> adjFlags)
{
int height;
int depth;
int minY = getMinY();
int maxY = getMaxY();
long singleAdjDataPoint;
int singleAdjData;
byte singleAdjFlags;
/* TODO implement attached vertical face culling
//Up direction case
if(DataPointUtil.doesItExist(adjData.get(Direction.UP)))
{
height = DataPointUtil.getHeight(singleAdjDataPoint);
depth = DataPointUtil.getDepth(singleAdjDataPoint);
height = DataPointUtil.getHeight(singleAdjData);
depth = DataPointUtil.getDepth(singleAdjData);
}*/
//Down direction case
singleAdjDataPoint = adjData.get(LodDirection.DOWN)[0];
if(DataPointUtil.doesItExist(singleAdjDataPoint))
skyLights.get(LodDirection.DOWN)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
singleAdjData = adjData.get(LodDirection.DOWN)[0];
singleAdjFlags = adjFlags.get(LodDirection.DOWN)[0];
if(DataPointUtil.doesItExist(singleAdjFlags))
skyLights.get(LodDirection.DOWN)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
else
skyLights.get(LodDirection.DOWN)[0] = skyLights.get(LodDirection.UP)[0];
//other sided
//TODO clean some similar cases
for (LodDirection lodDirection : ADJ_DIRECTIONS)
{
long[] dataPoint = adjData.get(lodDirection);
if (dataPoint == null || DataPointUtil.isVoid(dataPoint[0]))
if (isCulled(lodDirection))
continue;
int[] data = adjData.get(lodDirection);
byte[] flags = adjFlags.get(lodDirection);
if (DataPointUtil.isVoid(flags[0]))
{
adjHeight.get(lodDirection)[0] = maxY;
adjDepth.get(lodDirection)[0] = minY;
@@ -351,15 +386,16 @@ public class VertexOptimizer
boolean toFinish = false;
int toFinishIndex = 0;
boolean allAbove = true;
for (i = 0; i < dataPoint.length; i++)
for (i = 0; i < flags.length; i++)
{
singleAdjDataPoint = dataPoint[i];
singleAdjData = data[i];
singleAdjFlags = flags[i];
if (DataPointUtil.isVoid(singleAdjDataPoint) || !DataPointUtil.doesItExist(singleAdjDataPoint))
if (DataPointUtil.isVoid(singleAdjFlags) || !DataPointUtil.doesItExist(singleAdjFlags))
break;
height = DataPointUtil.getHeight(singleAdjDataPoint);
depth = DataPointUtil.getDepth(singleAdjDataPoint);
height = DataPointUtil.getHeight(singleAdjData);
depth = DataPointUtil.getDepth(singleAdjData);
if (depth <= maxY)
{
@@ -372,12 +408,12 @@ public class VertexOptimizer
{
adjHeight.get(lodDirection)[0] = getMaxY();
adjDepth.get(lodDirection)[0] = getMinY();
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); //skyLights.get(Direction.UP)[0];
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags); //skyLights.get(Direction.UP)[0];
}
else
{
adjDepth.get(lodDirection)[faceToDraw] = getMinY();
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
}
faceToDraw++;
toFinish = false;
@@ -403,12 +439,12 @@ public class VertexOptimizer
{
adjHeight.get(lodDirection)[0] = getMaxY();
adjDepth.get(lodDirection)[0] = height;
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint); //skyLights.get(Direction.UP)[0];
skyLights.get(lodDirection)[0] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags); //skyLights.get(Direction.UP)[0];
}
else
{
adjDepth.get(lodDirection)[faceToDraw] = height;
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
}
toFinish = false;
faceToDraw++;
@@ -420,7 +456,7 @@ public class VertexOptimizer
// the adj data intersects the higher part of the current data
// we start the creation of a new face
adjHeight.get(lodDirection)[faceToDraw] = depth;
//skyLights.get(direction)[faceToDraw] = (byte) DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
//skyLights.get(direction)[faceToDraw] = (byte) DataPointUtil.getLightSkyAlt(singleAdjData);
firstFace = false;
toFinish = true;
toFinishIndex = i + 1;
@@ -436,7 +472,7 @@ public class VertexOptimizer
}
adjDepth.get(lodDirection)[faceToDraw] = height;
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
faceToDraw++;
adjHeight.get(lodDirection)[faceToDraw] = depth;
firstFace = false;
@@ -456,11 +492,12 @@ public class VertexOptimizer
else if (toFinish)
{
adjDepth.get(lodDirection)[faceToDraw] = minY;
if(toFinishIndex < dataPoint.length)
if(toFinishIndex < flags.length)
{
singleAdjDataPoint = dataPoint[toFinishIndex];
if (DataPointUtil.doesItExist(singleAdjDataPoint))
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjDataPoint);
singleAdjData = data[toFinishIndex];
singleAdjFlags = flags[toFinishIndex];
if (DataPointUtil.doesItExist(singleAdjFlags))
skyLights.get(lodDirection)[faceToDraw] = DataPointUtil.getLightSkyAlt(singleAdjData, singleAdjFlags);
else
skyLights.get(lodDirection)[faceToDraw] = skyLights.get(LodDirection.UP)[0];
}
@@ -488,6 +525,17 @@ 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.
*/
@@ -32,7 +32,7 @@ public interface LevelContainer
* @param index z position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addData(long data, int posX, int posZ, int index);
boolean addData(int color, int data, byte flags, int posX, int posZ, int index);
/**
* With this you can add data to the level container
@@ -41,7 +41,7 @@ public interface LevelContainer
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addVerticalData(long[] data, int posX, int posZ);
boolean addVerticalData(int[] color, int[] data, byte[] flags, int posX, int posZ);
/**
* With this you can add data to the level container
@@ -50,25 +50,18 @@ public interface LevelContainer
* @param posZ z position in the detail level
* @return true if correctly added, false otherwise
*/
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
* @param posZ z position in the detail level
* @return the data in long array format
*/
long getData(int posX, int posZ, int index);
/**
* 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
*/
long getSingleData(int posX, int posZ);
boolean addSingleData(int color, int data, byte flags, int posX, int posZ);
int getColor(int posX, int posZ, int verticalIndex);
int getData(int posX, int posZ, int index);
byte getFlags(int posX, int posZ, int index);
byte getSingleFlags(int posX, int posZ);
/**
* data is returned to ThreadMapUtil variables
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true only if the data exist
@@ -112,6 +105,4 @@ public interface LevelContainer
* @return data as a String
*/
int getMaxNumberOfLods();
void mergeMultiData(int posX, int posZ, long[] dataToMergeVertical, int inputVerticalData);
}
@@ -30,12 +30,7 @@ import com.seibel.lod.core.enums.config.VerticalQuality;
import com.seibel.lod.core.handlers.LodDimensionFileHandler;
import com.seibel.lod.core.objects.PosToGenerateContainer;
import com.seibel.lod.core.objects.PosToRenderContainer;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodThreadFactory;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.util.*;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
@@ -445,7 +440,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten.
*/
public Boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data, boolean dontSave)
public Boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, int color, int data, byte flags, boolean dontSave)
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -455,7 +450,7 @@ public class LodDimension
if (region == null)
return false;
boolean nodeAdded = region.addData(detailLevel, posX, posZ, verticalIndex, data);
boolean nodeAdded = region.addData(detailLevel, posX, posZ, verticalIndex, color, data, flags);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
@@ -487,7 +482,7 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten.
*/
public Boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data, boolean dontSave)
public Boolean addVerticalData(byte detailLevel, int posX, int posZ, int[] color, int[] data, byte[] flags, boolean dontSave)
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
@@ -497,7 +492,7 @@ public class LodDimension
if (region == null)
return false;
boolean nodeAdded = region.addVerticalData(detailLevel, posX, posZ, data);
boolean nodeAdded = region.addVerticalData(detailLevel, posX, posZ, color, data, flags);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
@@ -551,6 +546,7 @@ public class LodDimension
// We can use two type of generation scheduling
switch (CONFIG.client().worldGenerator().getGenerationPriority())
{
default:
case NEAR_FIRST:
//in the NEAR_FIRST generation scheduling we prioritize the nearest un-generated position to the player
//the chunk position to generate will be stored in a posToGenerate object
@@ -565,7 +561,9 @@ public class LodDimension
byte detailLevel;
int posX;
int posZ;
long data;
int color;
int data;
byte flags;
int numbChunksWide = (width) * 32;
int circleLimit = Integer.MAX_VALUE;
@@ -613,11 +611,11 @@ public class LodDimension
posX = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, detailLevel);
posZ = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, zChunkToCheck, detailLevel);
data = getSingleData(detailLevel, posX, posZ);
flags = getSingleFlags(detailLevel, posX, posZ);
//we will generate the position only if the current generation complexity is lower than the target one.
//an un-generated area will always have 0 generation
if (DataPointUtil.getGenerationMode(data) < complexity)
if (DataPointUtil.getGenerationMode(flags) < complexity)
{
posToGenerate.addPosToGenerate(detailLevel, posX, posZ);
if (maxDataToGenerate >= 0)
@@ -636,7 +634,7 @@ public class LodDimension
}
break;
default:
case FAR_FIRST:
//in the FAR_FIRST generation we dedicate part of the generation process to the far region with really
//low detail quality.
@@ -704,43 +702,52 @@ public class LodDimension
return region.getMaxVerticalData(detailLevel);
}
/**
* 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 getData(byte detailLevel, int posX, int posZ, int verticalIndex)
public int getColor(byte detailLevel, int posX, int posZ, int verticalIndex)
{
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.getData(detailLevel, posX, posZ, verticalIndex);
return 0;
else
return region.getColor(detailLevel, posX, posZ, verticalIndex);
}
/**
* 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)
public int getData(byte detailLevel, int posX, int posZ, int verticalIndex)
{
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 0;
else
return region.getData(detailLevel, posX, posZ, verticalIndex);
}
public byte getFlags(byte detailLevel, int posX, int posZ, int verticalIndex)
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
return region.getSingleData(detailLevel, posX, posZ);
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
return 0;
else
return region.getFlags(detailLevel, posX, posZ, verticalIndex);
}
public byte getSingleFlags(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 (byte) 0;
else
return region.getSingleFlags(detailLevel, posX, posZ);
}
/** Clears the given region */
@@ -909,39 +916,4 @@ 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.
}
}
}
}
@@ -154,7 +154,7 @@ public class LodRegion
* TODO this will always return true unless it has
* @return true if the data was added successfully
*/
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data)
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, int color, int data, byte flags)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
@@ -162,9 +162,11 @@ public class LodRegion
// The dataContainer could have null entries if the
// detailLevel changes.
if (this.dataContainer[detailLevel] == null)
{
this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
}
this.dataContainer[detailLevel].addData(data, posX, posZ, verticalIndex);
this.dataContainer[detailLevel].addData(color, data, flags, posX, posZ, verticalIndex);
return true;
}
@@ -175,50 +177,51 @@ public class LodRegion
* TODO this will always return true unless it has
* @return true if the data was added successfully
*/
public boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data)
public boolean addVerticalData(byte detailLevel, int posX, int posZ, int[] color, int[] data, byte[] flags)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//position is already relative
//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);
return this.dataContainer[detailLevel].addVerticalData(data, posX, posZ);
return this.dataContainer[detailLevel].addVerticalData(color, data, flags, posX, posZ);
}
/**
* Get the dataPoint at the given relative position.
* @return the data at the relative pos and detail level,
* 0 if the data doesn't exist.
*/
public long getData(byte detailLevel, int posX, int posZ, int verticalIndex)
public int getColor(byte detailLevel, int posX, int posZ, int verticalIndex)
{
return dataContainer[detailLevel].getColor(posX, posZ, verticalIndex);
}
public int getData(byte detailLevel, int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getData(posX, posZ, verticalIndex);
}
public byte getFlags(byte detailLevel, int posX, int posZ, int verticalIndex)
{
return dataContainer[detailLevel].getFlags(posX, posZ, verticalIndex);
}
/**
* Get the dataPoint at the given relative position.
* Get the flags at the given relative position.
* @return the data at the relative pos and detail level,
* 0 if the data doesn't exist.
*/
public long getSingleData(byte detailLevel, int posX, int posZ)
public byte getSingleFlags(byte detailLevel, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getSingleData(posX, posZ);
return dataContainer[detailLevel].getSingleFlags(posX, posZ);
}
/**
* Clears the datapoint at the given relative position
*/
public void clear(byte detailLevel, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[detailLevel].clear(posX, posZ);
}
@@ -361,6 +364,7 @@ public class LodRegion
posZ + regionPosZ * size);
}
else
{
//if (desiredLevel > detailLevel)
//{
// we have gone beyond the target Detail level
@@ -385,7 +389,7 @@ public class LodRegion
{
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z))
{
if (requireCorrectDetailLevel)
if (!requireCorrectDetailLevel)
childrenCount++;
else
getPosToRender(posToRender, childDetailLevel, childPosX + x, childPosZ + z, playerPosX, playerPosZ, requireCorrectDetailLevel);
@@ -394,7 +398,7 @@ public class LodRegion
}
if (requireCorrectDetailLevel)
if (!requireCorrectDetailLevel)
{
// If all the four children exist go deeper
if (childrenCount == 4)
@@ -411,6 +415,7 @@ public class LodRegion
}
}
}
}
}
@@ -453,8 +458,6 @@ public class LodRegion
*/
private void update(byte detailLevel, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[detailLevel].updateData(dataContainer[detailLevel - 1], posX, posZ);
}
@@ -464,12 +467,15 @@ public class LodRegion
*/
public boolean doesDataExist(byte detailLevel, int posX, int posZ)
{
if (detailLevel < minDetailLevel || dataContainer[detailLevel] == null)
if (detailLevel < minDetailLevel)
return false;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (dataContainer[detailLevel] == null)
return false;
return dataContainer[detailLevel].doesItExist(posX, posZ);
}
@@ -481,7 +487,7 @@ public class LodRegion
if (dataContainer[detailLevel].doesItExist(posX, posZ))
// We take the bottom information always
// TODO what does that mean? bottom of what?
return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleData(posX, posZ));
return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleFlags(posX, posZ));
else
return DistanceGenerationMode.NONE.complexity;
}
@@ -610,16 +616,4 @@ 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,7 +19,6 @@
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;
@@ -36,28 +35,21 @@ 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 final int[] dataContainerColor;
public final int[] dataContainerData;
public final byte[] dataContainerFlags;
public VerticalLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
maxVerticalData = DetailDistanceUtil.getMaxVerticalData(detailLevel);
dataContainer = new long[size * size * DetailDistanceUtil.getMaxVerticalData(detailLevel)];
final int i = size * size * maxVerticalData;
dataContainerColor = new int[i];
dataContainerData = new int[i];
dataContainerFlags = new byte[i];
}
@Override
@@ -69,41 +61,81 @@ public class VerticalLevelContainer implements LevelContainer
@Override
public void clear(int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = DataPointUtil.EMPTY_DATA;
{
final int i = (posX * size + posZ) * maxVerticalData + verticalIndex;
dataContainerColor[i] = 0;
dataContainerData[i] = 0;
dataContainerFlags[i] = 0;
}
}
@Override
public boolean addData(long data, int posX, int posZ, int verticalIndex)
public boolean addData(int color, int data, byte flags, int posX, int posZ, int verticalIndex)
{
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = data;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
final int i = (posX * size + posZ) * maxVerticalData + verticalIndex;
dataContainerColor[i] = color;
dataContainerData[i] = data;
dataContainerFlags[i] = flags;
return true;
}
@Override
public boolean addVerticalData(long[] data, int posX, int posZ)
public boolean addVerticalData(int[] color, int[] data, byte[] flags, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = data[verticalIndex];
{
final int i = (posX * size + posZ) * maxVerticalData + verticalIndex;
dataContainerColor[i] = color[verticalIndex];
dataContainerData[i] = data[verticalIndex];
dataContainerFlags[i] = flags[verticalIndex];
}
return true;
}
@Override
public boolean addSingleData(long data, int posX, int posZ)
public boolean addSingleData(int color, int data, byte flags, int posX, int posZ)
{
return addData(data, posX, posZ, 0);
return addData(color, data, flags, posX, posZ, 0);
}
@Override
public long getData(int posX, int posZ, int verticalIndex)
public int getColor(int posX, int posZ, int verticalIndex)
{
return dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex];
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerColor[(posX * size + posZ) * maxVerticalData + verticalIndex];
}
@Override
public int getData(int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerData[(posX * size + posZ) * maxVerticalData + verticalIndex];
}
@Override
public long getSingleData(int posX, int posZ)
public byte getFlags(int posX, int posZ, int verticalIndex)
{
return dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData];
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerFlags[(posX * size + posZ) * maxVerticalData + verticalIndex];
}
@Override
public byte getSingleFlags(int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainerFlags[(posX * size + posZ) * maxVerticalData];
}
@Override
@@ -120,7 +152,9 @@ public class VerticalLevelContainer implements LevelContainer
@Override
public boolean doesItExist(int posX, int posZ)
{
return DataPointUtil.doesItExist(getSingleData(posX, posZ));
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return DataPointUtil.doesItExist(dataContainerFlags[(posX * size + posZ) * maxVerticalData]);
}
public VerticalLevelContainer(byte[] inputData, int version)
@@ -128,69 +162,131 @@ public class VerticalLevelContainer implements LevelContainer
int tempMaxVerticalData;
int tempIndex;
int index = 0;
long newData;
detailLevel = inputData[index];
index++;
tempMaxVerticalData = inputData[index] & 0b01111111;
index++;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int x = size * size * tempMaxVerticalData;
long[] tempDataContainer = new long[x];
int[] tempDataContainerColor = new int[x];
int[] tempDataContainerData = new int[x];
byte[] tempDataContainerFlags = new byte[x];
if (version == 6)
{
long oldData;
for (int i = 0; i < x; i++)
{
newData = 0;
oldData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
oldData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
newData = DataPointUtil.createDataPoint(
DataPointUtil.getAlpha(newData),
DataPointUtil.getRed(newData),
DataPointUtil.getGreen(newData),
DataPointUtil.getBlue(newData),
DataPointUtil.getHeight(newData) - DataPointUtil.VERTICAL_OFFSET,
DataPointUtil.getDepth(newData) - DataPointUtil.VERTICAL_OFFSET,
DataPointUtil.getLightSky(newData),
DataPointUtil.getLightBlock(newData),
DataPointUtil.getGenerationMode(newData),
DataPointUtil.getFlag(newData)
/*
|a |a |a |a |r |r |r |r |
|r |r |r |r |g |g |g |g |
|g |g |g |g |b |b |b |b |
|b |b |b |b |h |h |h |h |
|h |h |h |h |h |h |d |d |
|d |d |d |d |d |d |d |d |
|bl |bl |bl |bl |sl |sl |sl |sl |
|l |l |f |g |g |g |v |e |
*/
DataPointUtil.createDataPoint(
(int)((oldData >> 60) << 4) + 15,
(int)(oldData >> 52) & 0xFF,
(int)(oldData >> 44) & 0xFF,
(int)(oldData >> 36) & 0xFF,
(int)(oldData >> 26) & 0x3FF - DataPointUtil.VERTICAL_OFFSET,
(int)(oldData >> 16) & 0x3FF - DataPointUtil.VERTICAL_OFFSET,
(int)(oldData >> 8) & 0xF,
(int)(oldData >> 12) & 0xF,
(int)(oldData >> 5) & 0x1,
((oldData >> 5) & 0x1) == 1
);
tempDataContainer[i] = newData;
tempDataContainerColor[i] = ThreadMapUtil.dataPointColor;
tempDataContainerData[i] = ThreadMapUtil.dataPointData;
tempDataContainerFlags[i] = ThreadMapUtil.dataPointFlags;
}
}
else //if (version == 7)
else if (version == 7)
{
long oldData;
for (int i = 0; i < x; i++)
{
newData = 0;
oldData = 0;
for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
oldData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index += 8;
tempDataContainer[i] = newData;
DataPointUtil.createDataPoint(
(int)((oldData >> 60) << 4) + 15,
(int)(oldData >> 52) & 0xFF,
(int)(oldData >> 44) & 0xFF,
(int)(oldData >> 36) & 0xFF,
(int)(oldData >> 26) & 0x3FF - DataPointUtil.VERTICAL_OFFSET - 64,
(int)(oldData >> 16) & 0x3FF - DataPointUtil.VERTICAL_OFFSET - 64,
(int)(oldData >> 8) & 0xF,
(int)(oldData >> 12) & 0xF,
(int)(oldData >> 5) & 0x1,
((oldData >> 5) & 0x1) == 1
);
tempDataContainerColor[i] = ThreadMapUtil.dataPointColor;
tempDataContainerData[i] = ThreadMapUtil.dataPointData;
tempDataContainerFlags[i] = ThreadMapUtil.dataPointFlags;
}
}
else //if (version == 8)
{
int color;
int data;
for (int i = 0; i < x; i++)
{
byte flags = inputData[index];
index++;
data = 0;
color = 0;
for (tempIndex = 0; tempIndex < 4; tempIndex++)
{
data += (((int) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
color += (((int) inputData[index + tempIndex + 4]) & 0xff) << (8 * tempIndex);
}
index += 8;
tempDataContainerColor[i] = color;
tempDataContainerData[i] = data;
tempDataContainerFlags[i] = flags;
}
}
if (tempMaxVerticalData > DetailDistanceUtil.getMaxVerticalData(detailLevel))
{
int tempMaxVerticalData2 = DetailDistanceUtil.getMaxVerticalData(detailLevel);
long[] dataToMerge = new long[tempMaxVerticalData];
long[] tempDataContainer2 = new long[size * size * tempMaxVerticalData2];
int[] dataToMergeColor = new int[tempMaxVerticalData];
int[] dataToMergeData = new int[tempMaxVerticalData];
byte[] dataToMergeFlags = new byte[tempMaxVerticalData];
int[] tempDataContainer2Color = new int[size * size * tempMaxVerticalData2];
int[] tempDataContainer2Data = new int[size * size * tempMaxVerticalData2];
byte[] tempDataContainer2Flags = new byte[size * size * tempMaxVerticalData2];
for (int i = 0; i < size * size; i++)
{
System.arraycopy(tempDataContainer, i * tempMaxVerticalData, dataToMerge, 0, tempMaxVerticalData);
dataToMerge = DataPointUtil.mergeMultiData(dataToMerge, tempMaxVerticalData, tempMaxVerticalData2);
System.arraycopy(dataToMerge, 0, tempDataContainer2, i * tempMaxVerticalData2, tempMaxVerticalData2);
System.arraycopy(tempDataContainerColor, i * tempMaxVerticalData, dataToMergeColor, 0, tempMaxVerticalData);
System.arraycopy(tempDataContainerData, i * tempMaxVerticalData, dataToMergeData, 0, tempMaxVerticalData);
System.arraycopy(tempDataContainerFlags, i * tempMaxVerticalData, dataToMergeFlags, 0, tempMaxVerticalData);
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, tempMaxVerticalData, tempMaxVerticalData2);
System.arraycopy(ThreadMapUtil.getRawVerticalDataArrayColor(), 0, tempDataContainer2Color, i * tempMaxVerticalData2, tempMaxVerticalData2);
System.arraycopy(ThreadMapUtil.getRawVerticalDataArrayData(), 0, tempDataContainer2Data, i * tempMaxVerticalData2, tempMaxVerticalData2);
System.arraycopy(ThreadMapUtil.getRawVerticalDataArrayFlags(), 0, tempDataContainer2Flags, i * tempMaxVerticalData2, tempMaxVerticalData2);
}
maxVerticalData = tempMaxVerticalData2;
this.dataContainer = tempDataContainer2;
this.dataContainerColor = tempDataContainer2Color;
this.dataContainerData = tempDataContainer2Data;
this.dataContainerFlags = tempDataContainer2Flags;
}
else
{
maxVerticalData = tempMaxVerticalData;
this.dataContainer = tempDataContainer;
this.dataContainerColor = tempDataContainerColor;
this.dataContainerData = tempDataContainerData;
this.dataContainerFlags = tempDataContainerFlags;
}
}
@@ -204,11 +300,15 @@ public class VerticalLevelContainer implements LevelContainer
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{
//We reset the array
long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(detailLevel);
int[] dataToMergeColor = ThreadMapUtil.getVerticalUpdateArrayColor(detailLevel);
int[] dataToMergeData = ThreadMapUtil.getVerticalUpdateArrayData(detailLevel);
byte[] dataToMergeFlags = ThreadMapUtil.getVerticalUpdateArrayFlags(detailLevel);
int lowerMaxVertical = dataToMerge.length / 4;
int lowerMaxVertical = dataToMergeFlags.length / 4;
int childPosX;
int childPosZ;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
@@ -216,10 +316,17 @@ public class VerticalLevelContainer implements LevelContainer
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++)
dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
{
final int i = (z * 2 + x) * lowerMaxVertical + verticalIndex;
dataToMergeColor[i] = lowerLevelContainer.getColor(childPosX, childPosZ, verticalIndex);
dataToMergeData[i] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
dataToMergeFlags[i] = lowerLevelContainer.getFlags(childPosX, childPosZ, verticalIndex);
}
}
}
mergeMultiData(posX, posZ, dataToMerge, lowerMaxVertical);
DataPointUtil.mergeMultiData(dataToMergeColor, dataToMergeData, dataToMergeFlags, lowerMaxVertical, getMaxVerticalData());
addVerticalData(ThreadMapUtil.getRawVerticalDataArrayColor(), ThreadMapUtil.getRawVerticalDataArrayData(), ThreadMapUtil.getRawVerticalDataArrayFlags(), posX, posZ);
}
@Override
@@ -228,7 +335,8 @@ public class VerticalLevelContainer implements LevelContainer
int index = 0;
int x = size * size;
int tempIndex;
long current;
int currentColor;
int currentData;
boolean allGenerated = true;
byte[] tempData = ThreadMapUtil.getSaveContainer(detailLevel);
@@ -241,12 +349,18 @@ public class VerticalLevelContainer implements LevelContainer
{
for (j = 0; j < maxVerticalData; j++)
{
current = dataContainer[i * maxVerticalData + j];
for (tempIndex = 0; tempIndex < 8; tempIndex++)
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
currentColor = dataContainerColor[i * maxVerticalData + j];
currentData = dataContainerData[i * maxVerticalData + j];
tempData[index] = dataContainerFlags[i * maxVerticalData + j];
index++;
for (tempIndex = 0; tempIndex < 4; tempIndex++)
{
tempData[index + tempIndex] = (byte) (currentData >>> (8 * tempIndex));
tempData[index + tempIndex + 4] = (byte) (currentColor >>> (8 * tempIndex));
}
index += 8;
}
if(!DataPointUtil.doesItExist(dataContainer[i]))
if(!DataPointUtil.doesItExist(dataContainerFlags[i]))
allGenerated = false;
}
if (allGenerated)
@@ -254,325 +368,6 @@ 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()
@@ -26,7 +26,7 @@ import com.google.common.collect.ImmutableList;
* DefaultVertexFormats class.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-13-2021
*/
public class DefaultLodVertexFormats
{
@@ -37,8 +37,6 @@ public class DefaultLodVertexFormats
public static final LodVertexFormatElement ELEMENT_NORMAL = new LodVertexFormatElement(0, LodVertexFormatElement.DataType.BYTE, 3);
public static final LodVertexFormatElement ELEMENT_PADDING = new LodVertexFormatElement(0, LodVertexFormatElement.DataType.BYTE, 1);
public static final LodVertexFormatElement ELEMENT_BLOCK_LIGHT = new LodVertexFormatElement(0, LodVertexFormatElement.DataType.UBYTE, 1);
public static final LodVertexFormat POSITION = new LodVertexFormat(ImmutableList.<LodVertexFormatElement>builder().add(ELEMENT_POSITION).build());
public static final LodVertexFormat POSITION_COLOR = new LodVertexFormat(ImmutableList.<LodVertexFormatElement>builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).build());
@@ -47,5 +45,4 @@ public class DefaultLodVertexFormats
public static final LodVertexFormat POSITION_COLOR_TEX = new LodVertexFormat(ImmutableList.<LodVertexFormatElement>builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV).build());
public static final LodVertexFormat POSITION_COLOR_TEX_LIGHTMAP = new LodVertexFormat(ImmutableList.<LodVertexFormatElement>builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV).add(ELEMENT_LIGHT_MAP_UV).build());
public static final LodVertexFormat POSITION_COLOR_BLOCK_LIGHT_SKY_LIGHT = new LodVertexFormat(ImmutableList.<LodVertexFormatElement>builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_BLOCK_LIGHT).add(ELEMENT_BLOCK_LIGHT).build());
}
@@ -19,6 +19,7 @@
package com.seibel.lod.core.objects.opengl;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
@@ -37,7 +38,7 @@ import com.google.common.collect.Lists;
* OpenGL buffers.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-13-2021
*/
public class LodBufferBuilder
{
@@ -353,22 +354,7 @@ public class LodBufferBuilder
}
}
public LodBufferBuilder minecraftLightValue(byte lightValue)
{
LodVertexFormatElement LodVertexFormatelement = this.currentElement();
if (LodVertexFormatelement.getType() != LodVertexFormatElement.DataType.UBYTE)
{
throw new IllegalStateException("Light Color must be stored as a UBYTE");
}
else
{
this.putByte(0, lightValue);
this.nextElement();
return this;
}
}
public LodBufferBuilder position(float x, float y, float z)
public LodBufferBuilder vertex(float x, float y, float z)
{
if (this.currentElement().getType() != LodVertexFormatElement.DataType.FLOAT)
{
@@ -19,7 +19,7 @@
package com.seibel.lod.core.render;
import java.io.FileNotFoundException;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -57,7 +57,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
* https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer <br><br>
*
* @author James Seibel
* @version 12-8-2021
* @version 12-1-2021
*/
public class GLProxy
{
@@ -90,8 +90,6 @@ public class GLProxy
public LodShaderProgram lodShaderProgram;
/** This is the VAO that is used when rendering */
public final int vertexArrayObjectId;
/** This is the 2D texture that holds MC's lightmap */
public final int lightMapTextureId;
/** Requires OpenGL 4.5, and offers the best buffer uploading */
@@ -102,20 +100,18 @@ public class GLProxy
/**
* @throws IllegalStateException
* @throws RuntimeException
* @throws FileNotFoundException
*/
private GLProxy()
{
ClientApi.LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error.");
ClientApi.LOGGER.error("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error.");
// getting Minecraft's context has to be done on the render thread,
// where the GL context is
if (GLFW.glfwGetCurrentContext() == 0L)
throw new IllegalStateException(GLProxy.class.getSimpleName() + " was created outside the render thread!");
//============================//
// create the builder context //
//============================//
@@ -178,7 +174,7 @@ public class GLProxy
if (!bufferStorageSupported)
{
String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5";
ClientApi.LOGGER.warn("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance.");
ClientApi.LOGGER.error("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance.");
}
@@ -234,7 +230,6 @@ public class GLProxy
// this must be created on minecraft's render context to work correctly
vertexArrayObjectId = GL30.glGenVertexArrays();
lightMapTextureId = GL30.glGenTextures();
@@ -248,14 +243,10 @@ public class GLProxy
// GLProxy creation success
ClientApi.LOGGER.info(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
ClientApi.LOGGER.error(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
}
/**
* Creates all required shaders
* @throws RuntimeException
* @throws FileNotFoundException
*/
/** Creates all required shaders */
public void createShaderProgram()
{
LodShader vertexShader = null;
@@ -264,8 +255,8 @@ public class GLProxy
try
{
// get the shaders from the resource folder
vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "shaders/standard.vert", false);
fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "shaders/flat_shaded.frag", false);
vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "shaders" + File.separator + "standard.vert", false);
fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "shaders" + File.separator + "flat_shaded.frag", false);
// this can be used when testing shaders,
// since we can't hot swap the files in the resource folder
@@ -296,35 +287,6 @@ public class GLProxy
{
ClientApi.LOGGER.error("Unable to compile shaders. Error: " + e.getMessage());
}
// get the shaders from the resource folder
// Use File.separator ONLY if the file is external (not in the resourse), otherwise use "/"
vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "shaders/standard.vert", false);
fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "shaders/flat_shaded.frag", false);
// this can be used when testing shaders,
// since we can't hot swap the files in the resource folder
// vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "C:/Users/James Seibel/Desktop/shaders/standard.vert", true);
// fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "C:/Users/James Seibel/Desktop/shaders/flat_shaded.frag", true);
// create the shaders
lodShaderProgram = new LodShaderProgram();
// Attach the compiled shaders to the program, throws RuntimeException on link error
lodShaderProgram.attachShader(vertexShader);
lodShaderProgram.attachShader(fragmentShader);
// activate the fragment shader output
GL30.glBindFragDataLocation(lodShaderProgram.id, 0, "fragColor");
// attach the shader program to the OpenGL context
lodShaderProgram.link();
// after the shaders have been attached to the program
// we don't need their OpenGL references anymore
GL20.glDeleteShader(vertexShader.id);
GL20.glDeleteShader(fragmentShader.id);
}
@@ -22,13 +22,11 @@ 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;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.builders.bufferBuilding.LodBufferBuilderFactory;
import com.seibel.lod.core.builders.bufferBuilding.LodBufferBuilderFactory.VertexBuffersAndOffset;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
@@ -50,6 +48,8 @@ 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;
@@ -60,7 +60,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
* This is where LODs are draw to the world.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-27-2021
*/
public class LodRenderer
{
@@ -93,8 +93,7 @@ public class LodRenderer
@SuppressWarnings("unused")
private int[][][] storageBufferIds;
private int vbosCenterX = 0;
private int vbosCenterZ = 0;
private AbstractChunkPosWrapper vbosCenter = FACTORY.createChunkPos();
/** This is used to determine if the LODs should be regenerated */
@@ -193,7 +192,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().getX(), MC.getPlayerBlockPos().getY(), MC.getPlayerBlockPos().getZ(), true);
lodBufferBuilderFactory.generateLodBuffersAsync(this, lodDim, MC.getPlayerBlockPos(), true);
// the regen process has been started,
// it will be done when lodBufferBuilder.newBuffersAvailable()
@@ -279,13 +278,6 @@ public class LodRenderer
shaderProgram.enableVertexAttribute(posAttrib);
int colAttrib = shaderProgram.getAttributeLocation("color");
shaderProgram.enableVertexAttribute(colAttrib);
int blockSkyLightAttrib = shaderProgram.getAttributeLocation("blockSkyLight");
// TODO the block sky light is being passed in correctly but the data
// we were given appears to be incorrect, so we won't use it for now
//shaderProgram.enableVertexAttribute(blockSkyLightAttrib);
int blockLightAttrib = shaderProgram.getAttributeLocation("blockLight");
shaderProgram.enableVertexAttribute(blockLightAttrib);
// global uniforms
@@ -299,58 +291,6 @@ public class LodRenderer
shaderProgram.setUniform(fogColorUniform, getFogColor());
int skyLightUniform = shaderProgram.getUniformLocation("worldSkyLight");
shaderProgram.setUniform(skyLightUniform, (int) (MC.getSkyDarken(partialTicks) * 15));
int lightMapUniform = shaderProgram.getUniformLocation("lightMap");
GL20.glBindTexture(GL20.GL_TEXTURE_2D, glProxy.lightMapTextureId);
GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S, GL20.GL_CLAMP_TO_BORDER);
GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T, GL20.GL_CLAMP_TO_BORDER);
GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_NEAREST);
GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_NEAREST);
// get the latest lightmap from MC
try
{
int lightMapHeight = MC_RENDER.getLightmapTextureHeight();
int lightMapWidth = MC_RENDER.getLightmapTextureWidth();
int[] pixels = MC_RENDER.getLightmapPixels();
// comment me out to see when the lightmap is changing
// boolean same = true;
// int badIndex = 0;
// if (testArray != null && pixels != null)
// for (int i = 0; i < pixels.length; i++)
// {
// if(pixels[i] != testArray[i])
// {
// same = false;
// badIndex = i;
// break;
// }
// }
// testArray = pixels;
// MC.sendChatMessage(same + " " + badIndex);
// comment this line out to prevent uploading the new lightmap
GL20.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, lightMapWidth,
lightMapHeight, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixels);
// TODO is this needed/correct?
shaderProgram.setUniform(lightMapUniform, 0);
}
catch (Exception e)
{
ClientApi.LOGGER.info(e.getMessage(), e);
}
// region dependent uniforms
int fogEnabledUniform = shaderProgram.getUniformLocation("fogEnabled");
int nearFogEnabledUniform = shaderProgram.getUniformLocation("nearFogEnabled");
@@ -376,10 +316,8 @@ 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)
int vboCenterRegionPosX = vbosCenterX;
int vboCenterRegionPosZ = vbosCenterZ;
int vboPosX;
int vboPosZ;
RegionPos vboCenterRegionPos = new RegionPos(vbosCenter);
RegionPos vboPos = new RegionPos();
// render each of the buffers
@@ -387,13 +325,10 @@ public class LodRenderer
{
for (int z = 0; z < vbos.length; z++)
{
vboPosX = x + vboCenterRegionPosX - (lodDim.getWidth() / 2);
vboPosZ = z + vboCenterRegionPosZ - (lodDim.getWidth() / 2);
vboPos.x = x + vboCenterRegionPos.x - (lodDim.getWidth() / 2);
vboPos.z = z + vboCenterRegionPos.z - (lodDim.getWidth() / 2);
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)))
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(MC_RENDER.getCameraBlockPosition(), MC_RENDER.getLookAtVector(), vboPos.blockPos()))
{
// fog may be different from region to region
applyFog(shaderProgram,
@@ -406,7 +341,7 @@ public class LodRenderer
for (int i = 0; i < vbos[x][z].length; i++)
{
bufferId = (storageBufferIds != null && renderBufferStorage) ? storageBufferIds[x][z][i] : vbos[x][z][i].id;
drawArrays(bufferId, vbos[x][z][i].vertexCount, posAttrib, colAttrib, blockLightAttrib, blockSkyLightAttrib);
drawArrays(bufferId, vbos[x][z][i].vertexCount, posAttrib, colAttrib);
}
}
@@ -414,21 +349,18 @@ public class LodRenderer
}
GL20.glBindTexture(GL20.GL_TEXTURE_2D, 0);
//================//
// render cleanup //
//================//
// if this cleanup isn't done MC will crash
// if this cleanup isn't done MC may crash
// when trying to render its own terrain
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
GL20.glDisableVertexAttribArray(posAttrib);
GL20.glDisableVertexAttribArray(colAttrib);
// GL20.glDisableVertexAttribArray(blockSkyLightAttrib);
GL20.glDisableVertexAttribArray(blockLightAttrib);
}
@@ -455,10 +387,8 @@ public class LodRenderer
// end of internal LOD profiling
profiler.pop();
}
// Temporary variables James was using while working with the shader lightmap
int[] testArray = null;
int testInt = 0;
@@ -466,14 +396,14 @@ public class LodRenderer
/** This is where the actual drawing happens. */
private void drawArrays(int glBufferId, int vertexCount, int posAttrib, int colAttrib, int blockLightAttrib, int blockSkyLightAttrib)
private void drawArrays(int glBufferId, int vertexCount, int posAttrib, int colAttrib)
{
if (glBufferId == 0)
return;
// can be used to check for OpenGL errors
// int error = GL15.glGetError();
// ClientApi.LOGGER.info(Integer.toHexString(error));
// ClientProxy.LOGGER.info(Integer.toHexString(error));
// bind the buffer we are going to draw
@@ -481,15 +411,11 @@ public class LodRenderer
GL30.glBindVertexArray(GLProxy.getInstance().vertexArrayObjectId);
// let OpenGL know how our buffer is set up
int vertexByteCount = (Float.BYTES * 3) + (Byte.BYTES * 4) + Byte.BYTES + Byte.BYTES; // TODO move this into the template
int vertexByteCount = (Float.BYTES * 3) + (Byte.BYTES * 4);
GL20.glEnableVertexAttribArray(posAttrib);
GL20.glVertexAttribPointer(posAttrib, 3, GL15.GL_FLOAT, false, vertexByteCount, 0);
GL20.glEnableVertexAttribArray(colAttrib);
GL20.glVertexAttribPointer(colAttrib, 4, GL15.GL_UNSIGNED_BYTE, true, vertexByteCount, Float.BYTES * 3);
GL20.glEnableVertexAttribArray(blockLightAttrib);
GL20.glVertexAttribPointer(blockLightAttrib, 1, GL15.GL_UNSIGNED_BYTE, false, vertexByteCount, Float.BYTES * (3 + 1));
// GL20.glEnableVertexAttribArray(blockSkyLightAttrib);
// GL20.glVertexAttribPointer(blockSkyLightAttrib, 1, GL15.GL_UNSIGNED_BYTE, false, vertexByteCount, Float.BYTES * (3 + 1 + 1));
// draw the LODs
@@ -536,12 +462,12 @@ public class LodRenderer
// far fog //
if (CONFIG.client().graphics().fogQuality().getFogDistance() == FogDistance.NEAR_AND_FAR)
fogConfig.farFogStart = farPlaneBlockDistance * 0.9f;
fogConfig.farFogStart = farPlaneBlockDistance * 1.6f * 0.9f;
else
// for more realistic fog when using FAR
fogConfig.farFogStart = Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f);
fogConfig.farFogStart = Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f * 1.6f);
fogConfig.farFogEnd = farPlaneBlockDistance;
fogConfig.farFogEnd = farPlaneBlockDistance * 1.6f;
// near fog //
@@ -584,10 +510,9 @@ 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)
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;
AbstractBlockPosWrapper bufferPos = vbosCenter.getWorldPosition();
double xDiff = projectedView.x - bufferPos.getX();
double zDiff = projectedView.z - bufferPos.getZ();
mcModelViewMatrix.multiplyTranslationMatrix(-xDiff, -projectedView.y, -zDiff);
return mcModelViewMatrix;
@@ -599,10 +524,9 @@ public class LodRenderer
*/
private Vec3f getTranslatedCameraPos()
{
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);
AbstractBlockPosWrapper worldCenter = vbosCenter.getWorldPosition();
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
return new Vec3f((float)cameraPos.x - worldCenterX, (float)cameraPos.y, (float)cameraPos.z - worldCenterZ);
return new Vec3f((float)cameraPos.x - worldCenter.getX(), (float)cameraPos.y, (float)cameraPos.z - worldCenter.getZ());
}
/**
@@ -678,8 +602,7 @@ public class LodRenderer
VertexBuffersAndOffset result = lodBufferBuilderFactory.getVertexBuffers();
vbos = result.vbos;
storageBufferIds = result.storageBufferIds;
vbosCenterX = result.drawableCenterChunkPosX;
vbosCenterZ = result.drawableCenterChunkPosZ;
vbosCenter = result.drawableCenterChunkPos;
}
/** Calls the BufferBuilder's destroyBuffers method. */
@@ -739,7 +662,7 @@ public class LodRenderer
}
/*
// determine how far the lighting has to
// change in order to rebuild the buffers
@@ -771,6 +694,12 @@ public class LodRenderer
fullRegen = true;
prevBrightness = MC_RENDER.getGamma();
prevSkyBrightness = skyBrightness;
}
/*if (lightMap != lastLightMap)
{
fullRegen = true;
lastLightMap = lightMap;
}*/
//================//
@@ -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, int vboCenterPosX, int vboCenterPosZ)
public static boolean isRegionInViewFrustum(AbstractBlockPosWrapper playerBlockPos, Vec3f cameraDir, AbstractBlockPosWrapper vboCenterPos)
{
// convert the vbo position into a direction vector
// starting from the player's position
Vec3f vboVec = new Vec3f(vboCenterPosX, 0, vboCenterPosZ);
Vec3f vboVec = new Vec3f(vboCenterPos.getX(), 0, vboCenterPos.getZ());
Vec3f playerVec = new Vec3f(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ());
vboVec.subtract(playerVec);
@@ -21,13 +21,14 @@ package com.seibel.lod.core.render.shader;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.lwjgl.opengl.GL20;
import com.seibel.lod.core.api.ClientApi;
/**
* This object holds a OpenGL reference to a shader
* and allows for reading in and compiling a shader file.
@@ -58,23 +59,14 @@ public class LodShader
* @param absoluteFilePath If false the file path is relative to the resource jar folder.
* @throws Exception if the shader fails to compile
*/
public static LodShader loadShader(int type, String path, boolean absoluteFilePath)
public static LodShader loadShader(int type, String path, boolean absoluteFilePath) throws Exception
{
StringBuilder stringBuilder = new StringBuilder();
try
{
// open the file
InputStream in;
if (absoluteFilePath) {
// Throws FileNotFoundException
in = new FileInputStream(path); // Note: this should use OS path seperator
} else {
in = LodShader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
if (in == null) {
throw new FileNotFoundException("Shader file not found in resource: "+path);
}
}
InputStream in = absoluteFilePath ? new FileInputStream(path) : LodShader.class.getClassLoader().getResourceAsStream(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// read in the file
@@ -84,7 +76,7 @@ public class LodShader
}
catch (IOException e)
{
throw new RuntimeException("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
ClientApi.LOGGER.error("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
}
CharSequence shaderFileSource = stringBuilder.toString();
@@ -98,7 +90,7 @@ public class LodShader
* @param source Source of the shader
* @throws Exception if the shader fails to compile
*/
public static LodShader createShader(int type, CharSequence source)
public static LodShader createShader(int type, CharSequence source) throws Exception
{
LodShader shader = new LodShader(type);
GL20.glShaderSource(shader.id, source);
@@ -111,14 +103,14 @@ public class LodShader
* Compiles the shader and checks its status afterwards.
* @throws Exception if the shader fails to compile
*/
public void compile()
public void compile() throws Exception
{
GL20.glCompileShader(id);
// check if the shader compiled
int status = GL20.glGetShaderi(id, GL20.GL_COMPILE_STATUS);
if (status != GL20.GL_TRUE)
throw new RuntimeException("Shader compiler error. Details: "+GL20.glGetShaderInfoLog(id));
throw new Exception(GL20.glGetShaderInfoLog(id));
}
}
@@ -73,7 +73,7 @@ public class LodShaderProgram
* Links the shader program to the current OpenGL context.
* @throws Exception Exception if the program failed to link
*/
public void link()
public void link() throws Exception
{
GL20.glLinkProgram(this.id);
checkLinkStatus();
@@ -83,11 +83,11 @@ public class LodShaderProgram
* Checks if the program was linked successfully.
* @throws Exception if the program failed to link
*/
public void checkLinkStatus()
public void checkLinkStatus() throws Exception
{
int status = GL20.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
if (status != GL20.GL_TRUE)
throw new RuntimeException("Shader Link Error. Details: "+GL20.glGetProgramInfoLog(this.id));
throw new Exception(GL20.glGetProgramInfoLog(this.id));
}
@@ -57,9 +57,9 @@ public class DataPointUtil
//To be used in the future for negative value
//public final static int MIN_DEPTH = -64;
//public final static int MIN_HEIGHT = -64;
public final static int EMPTY_DATA = 0;
public static final short VERTICAL_OFFSET = -64;
public static int WORLD_HEIGHT = 1024;
public final static byte EMPTY_DATA = 0;
public static final short VERTICAL_OFFSET = -2048;
public static int WORLD_HEIGHT = 4096;
public final static int ALPHA_DOWNSIZE_SHIFT = 4;
@@ -68,167 +68,159 @@ public class DataPointUtil
//public final static int RED_COLOR_SHIFT = 16;
//public final static int ALPHA_COLOR_SHIFT = 24;
public final static int BLUE_SHIFT = 36;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24;
public final static byte BLUE_SHIFT = 0;
public final static byte GREEN_SHIFT = 8;
public final static byte RED_SHIFT = 16;
public final static byte ALPHA_SHIFT = 24;
public final static int COLOR_SHIFT = 36;
//public final static byte COLOR_SHIFT = 36;
public final static int HEIGHT_SHIFT = 26;
public final static int DEPTH_SHIFT = 16;
public final static int BLOCK_LIGHT_SHIFT = 12;
public final static int SKY_LIGHT_SHIFT = 8;
//public final static int LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
//public final static int VERTICAL_INDEX_SHIFT = 6;
public final static int FLAG_SHIFT = 5;
public final static int GEN_TYPE_SHIFT = 2;
public final static int VOID_SHIFT = 1;
public final static int EXISTENCE_SHIFT = 0;
public final static byte HEIGHT_SHIFT = 20;
public final static byte DEPTH_SHIFT = 8;
public final static byte BLOCK_LIGHT_SHIFT = 4;
public final static byte SKY_LIGHT_SHIFT = 0;
//public final static byte LIGHTS_SHIFT = SKY_LIGHT_SHIFT;
//public final static byte VERTICAL_INDEX_SHIFT = 6;
public final static byte FLAG_SHIFT = 5;
public final static byte GEN_TYPE_SHIFT = 2;
public final static byte VOID_SHIFT = 1;
public final static byte EXISTENCE_SHIFT = 0;
public final static long ALPHA_MASK = 0b1111;
public final static long RED_MASK = 0b1111_1111;
public final static long GREEN_MASK = 0b1111_1111;
public final static long BLUE_MASK = 0b1111_1111;
public final static long COLOR_MASK = 0b11111111_11111111_11111111;
public final static long HEIGHT_MASK = 0b11_1111_1111;
public final static long DEPTH_MASK = 0b11_1111_1111;
//public final static long LIGHTS_MASK = 0b1111_1111;
public final static long BLOCK_LIGHT_MASK = 0b1111;
public final static long SKY_LIGHT_MASK = 0b1111;
//public final static long VERTICAL_INDEX_MASK = 0b11;
public final static long FLAG_MASK = 0b1;
public final static long GEN_TYPE_MASK = 0b111;
public final static long VOID_MASK = 1;
public final static long EXISTENCE_MASK = 1;
public final static int ALPHA_MASK = 0xFF;
public final static int RED_MASK = 0xFF;
public final static int GREEN_MASK = 0xFF;
public final static int BLUE_MASK = 0xFF;
public final static int COLOR_MASK = 0xFFFFFFFF;
public final static int HEIGHT_MASK = 0xFFF;
public final static int DEPTH_MASK = 0xFFF;
public final static int LIGHTS_MASK = 0xFF;
public final static int BLOCK_LIGHT_MASK = 0xF;
public final static int SKY_LIGHT_MASK = 0xF;
public final static int VERTICAL_INDEX_MASK = 0x3;
public final static byte FLAG_MASK = 0x1;
public final static byte GEN_TYPE_MASK = 0x7;
public final static byte VOID_MASK = 1;
public final static byte EXISTENCE_MASK = 1;
public static long createVoidDataPoint(int generationMode)
/** Returns the Flags byte */
public static byte createVoidDataPoint(byte generationMode)
{
long dataPoint = 0;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
dataPoint += VOID_MASK << VOID_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
generationMode = (byte) ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT);
generationMode |= VOID_MASK << VOID_SHIFT;
generationMode |= EXISTENCE_MASK << EXISTENCE_SHIFT;
return generationMode;
}
public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode, boolean flag)
/** Returned datapoint is in ThreadMapUtil */
public static void createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode, boolean flag)
{
return createDataPoint(
ColorUtil.getAlpha(color),
ColorUtil.getRed(color),
ColorUtil.getGreen(color),
ColorUtil.getBlue(color),
height, depth, lightSky, lightBlock, generationMode, flag);
int data = (height & HEIGHT_MASK) << HEIGHT_SHIFT;
data += (depth & DEPTH_MASK) << DEPTH_SHIFT;
data += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
data += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
byte flags = (byte) ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT);
if (flag) flags += FLAG_MASK << FLAG_SHIFT;
flags += EXISTENCE_MASK << EXISTENCE_SHIFT;
ThreadMapUtil.saveDataPoint(color, data, flags);
}
public static long createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode, boolean flag)
public static void createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode, boolean flag)
{
long dataPoint = 0;
dataPoint += (long) (alpha >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT;
dataPoint += (red & RED_MASK) << RED_SHIFT;
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT;
dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT;
dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT;
dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT;
dataPoint += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT;
dataPoint += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT;
dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
if (flag) dataPoint += FLAG_MASK << FLAG_SHIFT;
dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT;
return dataPoint;
createDataPoint(
height, depth,
(alpha << ALPHA_SHIFT) | (red << RED_SHIFT) | (green << GREEN_SHIFT) | blue,
lightSky, lightBlock, generationMode, flag);
}
public static short getHeight(long dataPoint)
public static short getHeight(int data)
{
return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK);
return (short) ((data >>> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(long dataPoint)
public static short getDepth(int data)
{
return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK);
return (short) ((data >>> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getAlpha(long dataPoint)
public static short getAlpha(int color)
{
return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111);
return (short) ((color >>> ALPHA_SHIFT) & ALPHA_MASK);
}
public static short getRed(long dataPoint)
public static short getRed(int color)
{
return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK);
return (short) ((color >>> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
public static short getGreen(int color)
{
return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK);
return (short) ((color >>> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
public static short getBlue(int color)
{
return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK);
return (short) ((color >>> BLUE_SHIFT) & BLUE_MASK);
}
public static byte getLightSky(long dataPoint)
public static byte getLightSky(int data)
{
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
return (byte) ((data >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightSkyAlt(long dataPoint)
public static byte getLightSkyAlt(int data, byte flags)
{
if (skyLightPlayer == 0 && ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1)
if (skyLightPlayer == 0 && ((flags >>> FLAG_SHIFT) & FLAG_MASK) == 1)
return 0;
else
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
return (byte) ((data >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightBlock(long dataPoint)
public static byte getLightBlock(int data)
{
return (byte) ((dataPoint >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
return (byte) ((data >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
public static boolean getFlag(long dataPoint)
public static boolean getFlag(byte flags)
{
return ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1;
return ((flags >>> FLAG_SHIFT) & FLAG_MASK) == 1;
}
public static byte getGenerationMode(long dataPoint)
public static byte getGenerationMode(byte flags)
{
return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
return (byte) ((flags >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
}
public static boolean isVoid(long dataPoint)
public static boolean isVoid(byte flags)
{
return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1);
return (((flags >>> VOID_SHIFT) & VOID_MASK) == 1);
}
public static boolean doesItExist(long dataPoint)
public static boolean doesItExist(byte flags)
{
return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
return ((flags >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1;
}
public static int getColor(long dataPoint)
@Deprecated
public static int getColor(int color)
{
return (int) (((dataPoint >>> COLOR_SHIFT) & COLOR_MASK) | (/*((dataPoint >>> (ALPHA_SHIFT - ALPHA_DOWNSIZE_SHIFT)) | 0b1111)*/255 << 24));
return color;
}
/** This is used to convert a dataPoint to string (useful for the print function) */
@SuppressWarnings("unused")
public static String toString(long dataPoint)
public static String toString(int color, int data, byte flags)
{
return getHeight(dataPoint) + " " +
getDepth(dataPoint) + " " +
getAlpha(dataPoint) + " " +
getRed(dataPoint) + " " +
getBlue(dataPoint) + " " +
getGreen(dataPoint) + " " +
getLightBlock(dataPoint) + " " +
getLightSky(dataPoint) + " " +
getGenerationMode(dataPoint) + " " +
isVoid(dataPoint) + " " +
doesItExist(dataPoint) + '\n';
return getHeight(data) + " " +
getDepth(data) + " " +
getAlpha(color) + " " +
getRed(color) + " " +
getBlue(color) + " " +
getGreen(color) + " " +
getLightBlock(data) + " " +
getLightSky(data) + " " +
getGenerationMode(flags) + " " +
isVoid(flags) + " " +
doesItExist(flags) + '\n';
}
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize)
@@ -258,26 +250,30 @@ public class DataPointUtil
/**
* This method merge column of multiple data together
* @param dataToMerge one or more columns of data
* Returned datapoint is in ThreadMapUtil
* @param dataToMergeColor colors of one or more columns of data
* @param dataToMergeData data of one or more columns of data
* @param dataToMergeFlags flags of one or more columns of data
* @param inputVerticalData vertical size of an input data
* @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)
public static void mergeMultiData(int[] dataToMergeColor, int[] dataToMergeData, byte[] dataToMergeFlags, int inputVerticalData, int maxVerticalData)
{
int size = dataToMerge.length / inputVerticalData;
int size = dataToMergeData.length / inputVerticalData;
// We initialize the arrays that are going to be used
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((WORLD_HEIGHT / 2 + 1) * 2);
long[] dataPoint = ThreadMapUtil.getVerticalDataArray(DetailDistanceUtil.getMaxVerticalData(0));
int[] dataPointColor = ThreadMapUtil.getVerticalDataArrayColor(DetailDistanceUtil.getMaxVerticalData(0));
int[] dataPointData = ThreadMapUtil.getVerticalDataArrayData(DetailDistanceUtil.getMaxVerticalData(0));
byte[] dataPointFlags = ThreadMapUtil.getVerticalDataArrayFlags(DetailDistanceUtil.getMaxVerticalData(0));
int genMode = DistanceGenerationMode.FULL.complexity;
byte genMode = DistanceGenerationMode.FULL.complexity;
boolean allEmpty = true;
boolean allVoid = true;
boolean allDefault;
long singleData;
int singleDataData;
byte singleDataFlags;
short depth;
@@ -291,16 +287,17 @@ public class DataPointUtil
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (doesItExist(singleData))
singleDataData = dataToMergeData[index * inputVerticalData + dataIndex];
singleDataFlags = dataToMergeFlags[index * inputVerticalData + dataIndex];
if (doesItExist(singleDataFlags))
{
genMode = Math.min(genMode, getGenerationMode(singleData));
genMode = (byte) Math.min(genMode, getGenerationMode(singleDataFlags));
allEmpty = false;
if (!isVoid(singleData))
if (!isVoid(singleDataFlags))
{
allVoid = false;
depth = getDepth(singleData);
height = getHeight(singleData);
depth = getDepth(singleDataData);
height = getHeight(singleDataData);
int botPos = -1;
int topPos = -1;
@@ -403,11 +400,11 @@ public class DataPointUtil
//We check if there is any data that's not empty or void
if (allEmpty)
return dataPoint;
return;
if (allVoid)
{
dataPoint[0] = createVoidDataPoint(genMode);
return dataPoint;
dataPointFlags[0] = createVoidDataPoint(genMode);
return;
}
//we limit the vertical portion to maxVerticalData
@@ -452,71 +449,90 @@ public class DataPointUtil
allEmpty = true;
allVoid = true;
allDefault = true;
long data = 0;
int singleDataColor;
int data = EMPTY_DATA;
int color = EMPTY_DATA;
byte flags = EMPTY_DATA;
for (int index = 0; index < size; index++)
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (doesItExist(singleData) && !isVoid(singleData))
singleDataColor = dataToMergeColor[index * inputVerticalData + dataIndex];
singleDataData = dataToMergeData[index * inputVerticalData + dataIndex];
singleDataFlags = dataToMergeFlags[index * inputVerticalData + dataIndex];
if (doesItExist(singleDataFlags) && !isVoid(singleDataFlags))
{
if ((depth <= getDepth(singleData) && getDepth(singleData) <= height)
|| (depth <= getHeight(singleData) && getHeight(singleData) <= height))
if ((depth <= getDepth(singleDataData) && getDepth(singleDataData) <= height)
|| (depth <= getHeight(singleDataData) && getHeight(singleDataData) <= height))
{
if (getHeight(singleData) > getHeight(data))
data = singleData;
if (getHeight(singleDataData) > getHeight(data))
{
color = singleDataColor;
data = singleDataData;
flags = singleDataFlags;
}
}
}
else
break;
}
if (!doesItExist(data))
if (!doesItExist(flags))
{
singleData = dataToMerge[index * inputVerticalData];
data = createVoidDataPoint(getGenerationMode(singleData));
singleDataFlags = dataToMergeFlags[index * inputVerticalData];
if (doesItExist(singleDataFlags))
flags = createVoidDataPoint(getGenerationMode(singleDataFlags));
else
flags = createVoidDataPoint((byte) 0);
data = EMPTY_DATA;
color = EMPTY_DATA;
}
if (doesItExist(data))
if (doesItExist(flags))
{
allEmpty = false;
if (!isVoid(data))
if (!isVoid(flags))
{
numberOfChildren++;
allVoid = false;
tempAlpha += getAlpha(data);
tempRed += getRed(data);
tempGreen += getGreen(data);
tempBlue += getBlue(data);
tempAlpha += getAlpha(color);
tempRed += getRed(color);
tempGreen += getGreen(color);
tempBlue += getBlue(color);
tempLightBlock += getLightBlock(data);
tempLightSky += getLightSky(data);
if (!getFlag(data)) allDefault = false;
if (!getFlag(flags))
allDefault = false;
}
tempGenMode = (byte) Math.min(tempGenMode, getGenerationMode(data));
tempGenMode = (byte) Math.min(tempGenMode, getGenerationMode(flags));
}
else
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
}
if (allEmpty)
//no child has been initialized
dataPoint[j] = EMPTY_DATA;
else if (allVoid)
//all the children are void
dataPoint[j] = createVoidDataPoint(tempGenMode);
else
if (!allEmpty)
{
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
dataPoint[j] = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
//child has been initialized
if (allVoid)
{
//all the children are void
dataPointFlags[j] = 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;
createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
dataPointColor[j] = ThreadMapUtil.dataPointColor;
dataPointData[j] = ThreadMapUtil.dataPointData;
dataPointFlags[j] = ThreadMapUtil.dataPointFlags;
}
}
}
return dataPoint;
}
}
@@ -44,7 +44,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
* This class holds methods and constants that may be used in multiple places.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-13-2021
*/
public class LodUtil
{
@@ -140,7 +140,7 @@ public class LodUtil
public static final int MAX_ALLOCATABLE_DIRECT_MEMORY = 64 * 1024 * 1024;
/** the format of data stored in the GPU buffers */
public static final LodVertexFormat LOD_VERTEX_FORMAT = DefaultLodVertexFormats.POSITION_COLOR_BLOCK_LIGHT_SKY_LIGHT;
public static final LodVertexFormat LOD_VERTEX_FORMAT = DefaultLodVertexFormats.POSITION_COLOR;
@@ -38,15 +38,18 @@ import com.seibel.lod.core.objects.VertexOptimizer;
*/
public class ThreadMapUtil
{
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, int[][]> threadBuilderVerticalArrayMapColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> threadBuilderVerticalArrayMapData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[][]> threadBuilderVerticalArrayMapFlags = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[]> threadVerticalAddDataMapColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[]> threadVerticalAddDataMapData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[]> threadVerticalAddDataMapFlags = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[][]> saveContainer = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, short[]> projectionArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, short[]> heightAndDepthMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> verticalUpdate = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> verticalUpdateColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> verticalUpdateData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, byte[][]> verticalUpdateFlags = new ConcurrentHashMap<>();
//________________________//
@@ -54,9 +57,14 @@ public class ThreadMapUtil
//________________________//
public static final ConcurrentMap<String, boolean[]> adjShadeDisabled = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, long[]>> adjDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, int[]>> adjDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, Map<LodDirection, byte[]>> adjFlagsMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, VertexOptimizer> boxMap = new ConcurrentHashMap<>();
public static int dataPointColor = 0;
public static int dataPointData = 0;
public static byte dataPointFlags = 0;
/** returns the array NOT cleared every time */
@@ -72,7 +80,7 @@ public class ThreadMapUtil
}
/** returns the array NOT cleared every time */
public static Map<LodDirection, long[]> getAdjDataArray(int verticalData)
public static Map<LodDirection, int[]> getAdjDataArray(int verticalData)
{
if (!adjDataMap.containsKey(Thread.currentThread().getName())
|| (adjDataMap.get(Thread.currentThread().getName()) == null)
@@ -80,20 +88,41 @@ public class ThreadMapUtil
|| (adjDataMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData))
{
adjDataMap.put(Thread.currentThread().getName(), new HashMap<>());
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new long[1]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new long[1]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new int[1]);
adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new int[1]);
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new long[verticalData]);
adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new int[verticalData]);
}
else
{
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), DataPointUtil.EMPTY_DATA);
Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), 0);
}
return adjDataMap.get(Thread.currentThread().getName());
}
/** returns the array NOT cleared every time */
public static Map<LodDirection, byte[]> getAdjFlagsArray(int verticalData)
{
if (!adjFlagsMap.containsKey(Thread.currentThread().getName())
|| (adjFlagsMap.get(Thread.currentThread().getName()) == null)
|| (adjFlagsMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH) == null)
|| (adjFlagsMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData))
{
adjFlagsMap.put(Thread.currentThread().getName(), new HashMap<>());
adjFlagsMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new byte[1]);
adjFlagsMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new byte[1]);
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
adjFlagsMap.get(Thread.currentThread().getName()).put(lodDirection, new byte[verticalData]);
}
else
{
for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS)
Arrays.fill(adjFlagsMap.get(Thread.currentThread().getName()).get(lodDirection), (byte) 0);
}
return adjFlagsMap.get(Thread.currentThread().getName());
}
public static VertexOptimizer getBox()
{
if (!boxMap.containsKey(Thread.currentThread().getName())
@@ -119,21 +148,57 @@ public class ThreadMapUtil
/** returns the array filled with 0's */
public static long[] getBuilderVerticalArray(int detailLevel)
public static int[] getBuilderVerticalArrayColor(int detailLevel)
{
if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null))
if (!threadBuilderVerticalArrayMapColor.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[5][];
int[][] array = new int[5][];
int size;
for (int i = 0; i < 5; i++)
{
size = 1 << i;
array[i] = new long[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
array[i] = new int[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
}
threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array);
threadBuilderVerticalArrayMapColor.put(Thread.currentThread().getName(), array);
}
Arrays.fill(threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel];
Arrays.fill(threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMapColor.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static int[] getBuilderVerticalArrayData(int detailLevel)
{
if (!threadBuilderVerticalArrayMapData.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMapData.get(Thread.currentThread().getName()) == null))
{
int[][] array = new int[5][];
int size;
for (int i = 0; i < 5; i++)
{
size = 1 << i;
array[i] = new int[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
}
threadBuilderVerticalArrayMapData.put(Thread.currentThread().getName(), array);
}
Arrays.fill(threadBuilderVerticalArrayMapData.get(Thread.currentThread().getName())[detailLevel], 0);
return threadBuilderVerticalArrayMapData.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static byte[] getBuilderVerticalArrayFlags(int detailLevel)
{
if (!threadBuilderVerticalArrayMapFlags.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMapFlags.get(Thread.currentThread().getName()) == null))
{
byte[][] array = new byte[5][];
int size;
for (int i = 0; i < 5; i++)
{
size = 1 << i;
array[i] = new byte[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)];
}
threadBuilderVerticalArrayMapFlags.put(Thread.currentThread().getName(), array);
}
Arrays.fill(threadBuilderVerticalArrayMapFlags.get(Thread.currentThread().getName())[detailLevel], (byte) 0);
return threadBuilderVerticalArrayMapFlags.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array NOT cleared every time */
@@ -145,7 +210,7 @@ public class ThreadMapUtil
int size = 1;
for (int i = LodUtil.DETAIL_OPTIONS - 1; i >= 0; i--)
{
array[i] = new byte[2 + 8 * size * size * DetailDistanceUtil.getMaxVerticalData(i)];
array[i] = new byte[2 + 9 * size * size * DetailDistanceUtil.getMaxVerticalData(i)];
size = size << 1;
}
saveContainer.put(Thread.currentThread().getName(), array);
@@ -156,19 +221,46 @@ public class ThreadMapUtil
/** returns the array filled with 0's */
public static long[] getVerticalDataArray(int arrayLength)
public static int[] getVerticalDataArrayColor(int arrayLength)
{
if (!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null))
{
threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[arrayLength]);
}
if (!threadVerticalAddDataMapColor.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapColor.get(Thread.currentThread().getName()) == null))
threadVerticalAddDataMapColor.put(Thread.currentThread().getName(), new int[arrayLength]);
else
{
Arrays.fill(threadVerticalAddDataMap.get(Thread.currentThread().getName()), 0);
}
return threadVerticalAddDataMap.get(Thread.currentThread().getName());
Arrays.fill(threadVerticalAddDataMapColor.get(Thread.currentThread().getName()), 0);
return threadVerticalAddDataMapColor.get(Thread.currentThread().getName());
}
public static int[] getRawVerticalDataArrayColor()
{
return threadVerticalAddDataMapColor.get(Thread.currentThread().getName());
}
/** returns the array filled with 0's */
public static int[] getVerticalDataArrayData(int arrayLength)
{
if (!threadVerticalAddDataMapData.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapData.get(Thread.currentThread().getName()) == null))
threadVerticalAddDataMapData.put(Thread.currentThread().getName(), new int[arrayLength]);
else
Arrays.fill(threadVerticalAddDataMapData.get(Thread.currentThread().getName()), 0);
return threadVerticalAddDataMapData.get(Thread.currentThread().getName());
}
public static int[] getRawVerticalDataArrayData()
{
return threadVerticalAddDataMapData.get(Thread.currentThread().getName());
}
/** returns the array filled with 0's */
public static byte[] getVerticalDataArrayFlags(int arrayLength)
{
if (!threadVerticalAddDataMapFlags.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMapFlags.get(Thread.currentThread().getName()) == null))
threadVerticalAddDataMapFlags.put(Thread.currentThread().getName(), new byte[arrayLength]);
else
Arrays.fill(threadVerticalAddDataMapFlags.get(Thread.currentThread().getName()), (byte) 0);
return threadVerticalAddDataMapFlags.get(Thread.currentThread().getName());
}
public static byte[] getRawVerticalDataArrayFlags()
{
return threadVerticalAddDataMapFlags.get(Thread.currentThread().getName());
}
/** returns the array NOT cleared every time */
@@ -181,22 +273,49 @@ public class ThreadMapUtil
return heightAndDepthMap.get(Thread.currentThread().getName());
}
/** returns the array filled with 0's */
public static long[] getVerticalUpdateArray(int detailLevel)
public static int[] getVerticalUpdateArrayColor(int detailLevel)
{
if (!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null))
if (!verticalUpdateColor.containsKey(Thread.currentThread().getName()) || (verticalUpdateColor.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[LodUtil.DETAIL_OPTIONS][];
int[][] array = new int[LodUtil.DETAIL_OPTIONS][];
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new long[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdate.put(Thread.currentThread().getName(), array);
array[i] = new int[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdateColor.put(Thread.currentThread().getName(), array);
}
else
Arrays.fill(verticalUpdateColor.get(Thread.currentThread().getName())[detailLevel], 0);
return verticalUpdateColor.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static int[] getVerticalUpdateArrayData(int detailLevel)
{
if (!verticalUpdateData.containsKey(Thread.currentThread().getName()) || (verticalUpdateData.get(Thread.currentThread().getName()) == null))
{
Arrays.fill(verticalUpdate.get(Thread.currentThread().getName())[detailLevel], 0);
int[][] array = new int[LodUtil.DETAIL_OPTIONS][];
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new int[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdateData.put(Thread.currentThread().getName(), array);
}
return verticalUpdate.get(Thread.currentThread().getName())[detailLevel];
else
Arrays.fill(verticalUpdateData.get(Thread.currentThread().getName())[detailLevel], 0);
return verticalUpdateData.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static byte[] getVerticalUpdateArrayFlags(int detailLevel)
{
if (!verticalUpdateFlags.containsKey(Thread.currentThread().getName()) || (verticalUpdateFlags.get(Thread.currentThread().getName()) == null))
{
byte[][] array = new byte[LodUtil.DETAIL_OPTIONS][];
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
array[i] = new byte[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdateFlags.put(Thread.currentThread().getName(), array);
}
else
Arrays.fill(verticalUpdateFlags.get(Thread.currentThread().getName())[detailLevel], (byte) 0);
return verticalUpdateFlags.get(Thread.currentThread().getName())[detailLevel];
}
/** clears all arrays so they will have to be rebuilt */
@@ -205,14 +324,24 @@ public class ThreadMapUtil
adjShadeDisabled.clear();
adjDataMap.clear();
boxMap.clear();
threadSingleUpdateMap.clear();
threadBuilderArrayMap.clear();
threadBuilderVerticalArrayMap.clear();
threadVerticalAddDataMap.clear();
threadBuilderVerticalArrayMapColor.clear();
threadBuilderVerticalArrayMapData.clear();
threadBuilderVerticalArrayMapFlags.clear();
threadVerticalAddDataMapColor.clear();
threadVerticalAddDataMapData.clear();
threadVerticalAddDataMapFlags.clear();
saveContainer.clear();
projectionArrayMap.clear();
heightAndDepthMap.clear();
singleDataToMergeMap.clear();
verticalUpdate.clear();
verticalUpdateColor.clear();
verticalUpdateData.clear();
verticalUpdateFlags.clear();
}
public static void saveDataPoint(int color, int data, byte flags)
{
dataPointColor = color;
dataPointData = data;
dataPointFlags = flags;
}
}
@@ -31,8 +31,6 @@ public interface IBlockColorWrapper
boolean hasColor();
String getName();
int getColor();
@@ -23,8 +23,6 @@ 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
@@ -34,27 +32,21 @@ public interface IChunkWrapper
{
int getHeight();
boolean isPositionInWater(int x, int y, int z);
boolean isPositionInWater(AbstractBlockPosWrapper blockPos);
int getHeightMapValue(int xRel, 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);
IBiomeWrapper getBiome(int xRel, int yAbs, int zRel);
int getChunkPosX();
int getChunkPosZ();
int getRegionPosX();
int getRegionPosZ();
int getMaxY(int x, int z);
int getMaxX();
int getMaxZ();
int getMinX();
int getMinZ();
IBlockColorWrapper getBlockColorWrapper(AbstractBlockPosWrapper blockPos);
IBlockShapeWrapper getBlockShapeWrapper(AbstractBlockPosWrapper blockPos);
AbstractChunkPosWrapper getPos();
boolean isLightCorrect();
boolean isWaterLogged(int x, int y, int z);
boolean isWaterLogged(AbstractBlockPosWrapper blockPos);
int getEmittedBrightness(int x, int y, int z);
int getEmittedBrightness(AbstractBlockPosWrapper blockPos);
}
@@ -184,6 +184,17 @@ 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 = ""
@@ -440,7 +451,7 @@ public interface ILodConfigWrapperSingleton
boolean DEBUG_KEYBINDINGS_ENABLED_DEFAULT = true;
String DEBUG_KEYBINDINGS_ENABLED_DESC = ""
+ " If true the F8 key can be used to cycle through the different debug modes. \n"
+ " If true the F4 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);
@@ -33,7 +33,7 @@ import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
* rendering in Minecraft.
*
* @author James Seibel
* @version 12-8-2021
* @version 11-26-2021
*/
public interface IMinecraftRenderWrapper
{
@@ -66,14 +66,4 @@ public interface IMinecraftRenderWrapper
* is going to render this frame.
*/
HashSet<AbstractChunkPosWrapper> getRenderedChunks();
/** @returns null if there was a issue getting the lightmap */
int[] getLightmapPixels();
/** @returns -1 if there was an issue getting the lightmap */
int getLightmapTextureHeight();
/** @returns -1 if there was an issue getting the lightmap */
int getLightmapTextureWidth();
/** @returns -1 if there was an issue getting the lightmap */
public int getLightmapGLFormat();
}
@@ -34,7 +34,7 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
* Contains everything related to the Minecraft object.
*
* @author James Seibel
* @version 12-8-2021
* @version 9-16-2021
*/
public interface IMinecraftWrapper
{
@@ -77,18 +77,18 @@ public interface IMinecraftWrapper
/**
* Returns the color int at the given pixel coordinates
* from the current lightmap.
* @param blockLight x location in texture space
* @param skyLight z location in texture space
* @param u x location in texture space
* @param v z location in texture space
*/
int getColorIntFromLightMap(int blockLight, int skyLight);
int getColorIntFromLightMap(int u, int v);
/**
* Returns the Color at the given pixel coordinates
* from the current lightmap.
* @param blockLight x location in texture space
* @param skyLight z location in texture space
* @param u x location in texture space
* @param v z location in texture space
*/
Color getColorFromLightMap(int blockLight, int skyLight);
Color getColorFromLightMap(int u, int v);
@@ -28,8 +28,6 @@ public interface IBiomeWrapper
/** Returns a color int for the given biome. */
int getColorForBiome(int x, int z);
String getName();
int getGrassTint(int x, int z);
int getFolliageTint();
@@ -36,9 +36,11 @@ public interface IWorldWrapper
WorldType getWorldType();
int getBlockLight(int x, int y, int z);
int getBlockLight(AbstractBlockPosWrapper blockPos);
int getSkyLight(int x, int y, int z);
int getSkyLight(AbstractBlockPosWrapper blockPos);
IBiomeWrapper getBiome(AbstractBlockPosWrapper blockPos);
boolean hasCeiling();
+2 -1
View File
@@ -2,12 +2,13 @@
in vec4 vertexColor;
in vec4 vertexWorldPos;
//in vec2 textureCoord;
out vec4 fragColor;
//uniform sampler2D texImage;
uniform vec3 cameraPos;
uniform bool fogEnabled;
+4 -20
View File
@@ -2,46 +2,30 @@
in vec3 vPosition;
in vec4 color;
in float blockSkyLight;
in float blockLight;
out vec4 vertexColor;
out vec4 vertexWorldPos;
//out vec2 textureCoord;
out float depth;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform int worldSkyLight;
uniform sampler2D lightMap;
/**
* Vertex Shader
*
* author: James Seibel
* version: 12-8-2021
* version: 11-26-2021
*/
void main()
{
// just skylight
// good for sanity checks; but will cause OpenGL errors since we are binding unused data
// vertexColor = vec4(color.xyz * worldSkyLight / 16.0, color.w);
float blockLightTex = blockLight / 16.0;
float skyLightTex = blockSkyLight / 16.0;
// we don't really need alpha in the lightmap
// vertexColor = color * vec4(texture(lightMap, vec2(blockLightTex, skyLightTex)).xyz, 1);
vertexColor = color * texture(lightMap, vec2(blockLightTex, skyLightTex));
// TODO: add a simple white texture to support Optifine shaders
//textureCoord = textureCoord;
vertexColor = color;
vertexWorldPos = vec4(vPosition, 1);
// the vPosition needs to be converted to a vec4 so it can be multiplied