Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1860729256 | |||
| d0b0fae54e | |||
| 7786e1fea6 | |||
| e5ad718ed0 | |||
| bda34d0a6d | |||
| 2584afbd05 | |||
| 72e4b520db | |||
| 3220ad0f7a | |||
| aba99f8210 | |||
| 430579be28 | |||
| 30cc294a04 | |||
| aa79d5b5d4 | |||
| 509ae5aba0 |
@@ -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)
|
||||
|
||||
+71
-55
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-8
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
-21
@@ -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++;
|
||||
}
|
||||
|
||||
+2
-1
@@ -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!");
|
||||
|
||||
+2
-1
@@ -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);
|
||||
}
|
||||
|
||||
+12
-1
@@ -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);
|
||||
|
||||
+1
-11
@@ -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();
|
||||
}
|
||||
|
||||
+7
-7
@@ -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,12 +2,13 @@
|
||||
|
||||
in vec4 vertexColor;
|
||||
in vec4 vertexWorldPos;
|
||||
|
||||
//in vec2 textureCoord;
|
||||
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
||||
//uniform sampler2D texImage;
|
||||
uniform vec3 cameraPos;
|
||||
|
||||
uniform bool fogEnabled;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user