Merge branch '1.16.5' of https://gitlab.com/jeseibel/minecraft-lod-mod into vertical_merging

 Conflicts:
	src/main/java/com/seibel/lod/util/ThreadMapUtil.java
This commit is contained in:
cola98765
2021-09-19 10:36:33 +02:00
24 changed files with 962 additions and 725 deletions
+4 -12
View File
@@ -1,7 +1,6 @@
buildscript {
repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter()
maven { url = 'https://files.minecraftforge.net' }
mavenCentral()
// potential replacement in case of problems:
// https://dist.creeper.host/Sponge/maven
@@ -19,20 +18,13 @@ apply plugin: 'org.spongepowered.mixin'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
apply plugin: 'java' // needed for compileJava
version = 'a1.4.1'
group = 'com.seibel.lod'
archivesBaseName = 'lod_1.16.5'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
// release 8 is needed because otherwise FloatBuffer.flip() will crash
// on some machines
// example thread: https://github.com/eclipse/jetty.project/issues/3244
options.compilerArgs.addAll(['-Xlint:unchecked', '-Xlint:deprecation'])
}
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
@@ -200,7 +192,7 @@ jar {
"Specification-Title": "LOD",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "{version}",
"Implementation-Version": "1",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"MixinConfigs": "lod.mixins.json",
])
@@ -228,4 +220,4 @@ publishing {
mixin {
add sourceSets.main, "lod.refmap.json"
}
}
+36 -14
View File
@@ -1,11 +1,12 @@
package com.seibel.lod;
import com.google.common.primitives.UnsignedLong;
import com.seibel.lod.objects.PosToGenerateContainer;
import java.util.HashMap;
import java.util.Map;
import com.seibel.lod.builders.lodTemplates.Box;
import com.seibel.lod.util.DataPointUtil;
import javax.xml.crypto.Data;
import java.math.BigInteger;
import net.minecraft.util.Direction;
public class Main
{
@@ -13,18 +14,39 @@ public class Main
{
try
{
long[][] dataToMerge = new long[][]{
{DataPointUtil.createDataPoint(10, 5, 0, 0, 0, 0)},
{DataPointUtil.createDataPoint(15, 5, 0, 0, 0, 0)},
{DataPointUtil.createDataPoint(40, 20, 0, 0, 0, 0)},
{DataPointUtil.createDataPoint(1, 0, 0, 0, 0, 0)}};
long[] data = DataPointUtil.mergeVerticalData(dataToMerge);
for (long dataPoint : data)
@SuppressWarnings("serial")
Map<Direction, long[]> adjData = new HashMap<Direction, long[]>()
{{
put(Direction.EAST, new long[]{DataPointUtil.createDataPoint(60, 30, 0, 0, 0, 0), DataPointUtil.createDataPoint(25, 10, 0, 0, 0, 0)});
put(Direction.WEST, new long[]{DataPointUtil.createDataPoint(60, 10, 0, 0, 0, 0)});
put(Direction.NORTH, new long[]{DataPointUtil.createDataPoint(40, 20, 0, 0, 0, 0)});
put(Direction.SOUTH, new long[]{DataPointUtil.createDataPoint(40, 20, 0, 0, 0, 0)});
}};
Box box = new Box();
int height = 60;
int depth = 20;
box.set(10, height - depth, 10);
box.move(0, depth, 0);
box.setAdjData(adjData);
for(Direction direction : Box.DIRECTIONS)
{
System.out.println("depth " + DataPointUtil.getDepth(dataPoint));
System.out.println("height " + DataPointUtil.getHeight(dataPoint));
int adjIndex = 0;
while (box.shouldContinue(direction, adjIndex))
{
System.out.println(direction.toString());
for (int i = 0; i < 4; i++)
{
System.out.println(box.getX(direction, i) + " " + box.getY(direction, i, adjIndex) + " " + box.getZ(direction, i));
}
adjIndex++;
}
}
}catch (Exception e){
} catch (Exception e)
{
e.printStackTrace();
}
}
@@ -19,7 +19,9 @@ package com.seibel.lod.builders;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -48,6 +50,7 @@ import com.seibel.lod.util.LodUtil;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
@@ -110,9 +113,9 @@ public class LodBufferBuilder
*/
private ReentrantLock bufferLock = new ReentrantLock();
private static final int NUMBER_OF_DIRECTION = 4;
// private static final int NUMBER_OF_DIRECTION = 4;
//in order -x, +x, -z, +z
private static final int[][] ADJ_DIRECTION = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// private static final int[][] ADJ_VECTOR = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
private volatile Box[][] boxCache;
private volatile PosToRenderContainer[][] setsToRender;
@@ -169,7 +172,7 @@ public class LodBufferBuilder
long startTime = System.currentTimeMillis();
ArrayList<Callable<Boolean>> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length);
ArrayList<Callable<Boolean>> nodeToRenderThreads = new ArrayList<>(lodDim.getWidth() * lodDim.getWidth());
startBuffers(fullRegen, lodDim);
@@ -182,25 +185,25 @@ public class LodBufferBuilder
center = playerRegionPos;
if (setsToRender == null)
setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length];
setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()];
if (setsToRender.length != lodDim.regions.length)
setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length];
if (setsToRender.length != lodDim.getWidth())
setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()];
if (boxCache == null)
boxCache = new Box[lodDim.regions.length][lodDim.regions.length];
boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()];
if (boxCache.length != lodDim.regions.length)
boxCache = new Box[lodDim.regions.length][lodDim.regions.length];
if (boxCache.length != lodDim.getWidth())
boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++)
for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++)
{
for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++)
for (int zRegion = 0; zRegion < lodDim.getWidth(); zRegion++)
{
if (lodDim.regen[xRegion][zRegion] || fullRegen)
if (lodDim.getRegenByArrayIndex(xRegion, zRegion) || fullRegen)
{
RegionPos regionPos = new RegionPos(
xRegion + lodDim.getCenterX() - Math.floorDiv(lodDim.getWidth(), 2),
@@ -220,7 +223,14 @@ public class LodBufferBuilder
final int zR = zRegion;
Callable<Boolean> dataToRenderThread = () ->
{
Map<Direction, long[]> adjData = new HashMap<>();
if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP)
{
adjData.put(Direction.WEST, new long[1]);
adjData.put(Direction.EAST, new long[1]);
adjData.put(Direction.SOUTH, new long[1]);
adjData.put(Direction.NORTH, new long[1]);
}
//previous setToRender chache
if (setsToRender[xR][zR] == null)
{
@@ -247,10 +257,12 @@ public class LodBufferBuilder
int zAdj;
int chunkXdist;
int chunkZdist;
short gameChunkRenderDistance = (short) (renderer.vanillaRenderedChunks.length / 2 - 1);
//long dataPoint;
long[] adjData = new long[NUMBER_OF_DIRECTION];
// keep a local version so we don't have to worry about indexOutOfBounds Exceptions
// if it changes in the LodRenderer while we are working here
boolean[][] vanillaRenderedChunks = renderer.vanillaRenderedChunks;
short gameChunkRenderDistance = (short) (vanillaRenderedChunks.length / 2 - 1);
for (int index = 0; index < posToRender.getNumberOfPos(); index++)
{
detailLevel = posToRender.getNthDetailLevel(index);
@@ -262,63 +274,84 @@ public class LodBufferBuilder
if (gameChunkRenderDistance >= Math.abs(chunkXdist)
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
&& vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
{
continue;
}
// skip any chunks that Minecraft is going to render
try
{
for (Direction direction : Box.ADJ_DIRECTIONS)
{
xAdj = posX + direction.getNormal().getX();
zAdj = posZ + direction.getNormal().getZ();
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
{
if (!vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& posToRender.contains(detailLevel, xAdj, zAdj))
{
if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP)
{
adjData.get(direction)[0] = lodDim.getSingleData(detailLevel, xAdj, zAdj);
} else
{
adjData.put(direction, lodDim.getData(detailLevel, xAdj, zAdj));
}
} else
{
if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP)
{
adjData.get(direction)[0] = DataPointUtil.createVoidDataPoint(0);
} else
{
adjData.put(direction, null);
}
}
} else
{
if (posToRender.contains(detailLevel, xAdj, zAdj))
{
if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP)
{
adjData.get(direction)[0] = lodDim.getSingleData(detailLevel, xAdj, zAdj);
} else
{
adjData.put(direction, lodDim.getData(detailLevel, xAdj, zAdj));
}
} else
{
if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP)
{
adjData.get(direction)[0] = DataPointUtil.createVoidDataPoint(0);
} else
{
adjData.put(direction, null);
}
}
}
}
if (region.getLodQualityMode() == LodQualityMode.HEIGHTMAP)
{
//dataPoint = lodDim.getData(detailLevel, posX, posZ)[0];
long dataPoint = lodDim.getSingleData(detailLevel, posX, posZ);
if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint))
{
dataPoint = lodDim.getSingleData(detailLevel, posX, posZ);
if(DataPointUtil.getHeight(dataPoint) == LodBuilder.DEFAULT_HEIGHT && DataPointUtil.getDepth(dataPoint) == LodBuilder.DEFAULT_DEPTH)
continue;
for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++)
{
xAdj = posX + ADJ_DIRECTION[direction][0];
zAdj = posZ + ADJ_DIRECTION[direction][1];
chunkXdist = LevelPosUtil.getChunkPos(detailLevel,xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel,zAdj) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
{
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction]= lodDim.getSingleData(detailLevel, xAdj, zAdj);
}else{
adjData[direction]= 0;
}
} else
{
if (posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction] = lodDim.getSingleData(detailLevel, xAdj, zAdj);
}else{
adjData[direction]= 0;
}
}
}
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR],renderer.previousDebugMode, renderer.lightMap);
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap);
}
} else if (region.getLodQualityMode() == LodQualityMode.MULTI_LOD)
{
//dataPoint = lodDim.getData(detailLevel, posX, posZ)[0];
for (long dataPoint : lodDim.getData(detailLevel, posX, posZ))
{
if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint))
{
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap);
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap);
}
}
}
@@ -366,13 +399,11 @@ public class LodBufferBuilder
// mark that the buildable buffers as ready to swap
switchVbos = true;
}
catch (Exception e)
} catch (Exception e)
{
ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: ");
e.printStackTrace();
}
finally
} finally
{
// regardless of if we successfully created the buffers
// we are done generating.
@@ -385,9 +416,6 @@ public class LodBufferBuilder
// upload the new buffers
uploadBuffers(fullRegen, lodDim);
bufferLock.unlock();
// make sure the context is disabled
GlProxy.getInstance().setGlContext(GlProxyContext.NONE);
}
});
@@ -459,7 +487,7 @@ public class LodBufferBuilder
{
for (int z = 0; z < buildableBuffers.length; z++)
{
if (fullRegen || lodDim.regen[x][z])
if (fullRegen || lodDim.getRegenByArrayIndex(x, z))
{
buildableBuffers[x][z].begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT);
}
@@ -474,7 +502,7 @@ public class LodBufferBuilder
{
for (int x = 0; x < buildableBuffers.length; x++)
for (int z = 0; z < buildableBuffers.length; z++)
if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.regen[x][z]))
if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.getRegenByArrayIndex(x, z)))
buildableBuffers[x][z].end();
}
@@ -483,73 +511,78 @@ public class LodBufferBuilder
*/
private void uploadBuffers(boolean fullRegen, LodDimension lodDim)
{
GlProxy glProxy = GlProxy.getInstance();
try
{
GlProxy glProxy = GlProxy.getInstance();
// make sure we are uploading to a different OpenGL context,
// to prevent interference (IE stuttering) with the Minecraft context.
glProxy.setGlContext(GlProxyContext.LOD_BUILDER);
// only print console debugging for vboUpload once per upload cycle
boolean bufferMapFail = false;
for (int x = 0; x < buildableVbos.length; x++)
{
for (int z = 0; z < buildableVbos.length; z++)
{
if (fullRegen || lodDim.regen[x][z])
if (fullRegen || lodDim.getRegenByArrayIndex(x, z))
{
ByteBuffer builderBuffer = buildableBuffers[x][z].popNextBuffer().getSecond();
bufferMapFail = vboUpload(buildableVbos[x][z], builderBuffer, bufferMapFail);
lodDim.regen[x][z] = false;
vboUpload(buildableVbos[x][z], builderBuffer);
lodDim.setRegenByArrayIndex(x, z, false);
}
}
}
// make sure all the buffers have been uploaded.
// this probably is necessary, but it makes me feel good :)
GL11.glFlush();
glProxy.setGlContext(GlProxyContext.NONE);
}
catch(IllegalStateException e)
catch (IllegalStateException e)
{
ClientProxy.LOGGER.error(LodBufferBuilder.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage());
e.printStackTrace();
}
finally
{
// make sure no buffer is bound
if (glProxy.getGlContext() == GlProxyContext.LOD_BUILDER)
{
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
// make sure the context is disabled
glProxy.setGlContext(GlProxyContext.NONE);
}
}
/**
* Uploads the uploadBuffer into the VBO in GPU memory.
*/
private boolean vboUpload(VertexBuffer vbo, ByteBuffer uploadBuffer, boolean bufferMapFail)
private void vboUpload(VertexBuffer vbo, ByteBuffer uploadBuffer)
{
// this shouldn't happen, but just to be safe
if (vbo.id != -1)
{
// this is how many points will be rendered
vbo.vertexCount = (uploadBuffer.remaining() / vbo.format.getVertexSize());
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id);
// subData only works if the memory is allocated beforehand.
GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer.remaining(), GL15C.GL_DYNAMIC_DRAW);
// interestingly bufferSubData renders faster than glMapBuffer
// even though OpenGLInsights-AsynchronousBufferTransfers says glMapBuffer
// is faster for transferring data. They must put the data in different memory
// or something.
GL15C.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, uploadBuffer);
GL15C.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
// just used to improve debug printing
return bufferMapFail;
}
/**
@@ -29,13 +29,26 @@ import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.util.*;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.ThreadMapUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.block.*;
import net.minecraft.block.AbstractPlantBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.BushBlock;
import net.minecraft.block.GrassBlock;
import net.minecraft.block.IGrowable;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@@ -49,25 +62,24 @@ import net.minecraft.world.IWorld;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeColors;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.Heightmap;
import net.minecraftforge.client.extensions.IForgeBakedModel;
import net.minecraftforge.client.model.data.ModelDataMap;
import javax.swing.*;
/**
* This object is in charge of creating Lod related objects. (specifically: Lod
* World, Dimension, and Region objects)
*
* @author Leonardo Amato
* @author James Seibel
* @version 9-7-2021
* @version 9-18-2021
*/
public class LodBuilder
{
private static MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
private ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName()));
public static final int CHUNK_DATA_WIDTH = LodUtil.CHUNK_WIDTH;
@@ -118,20 +130,25 @@ public class LodBuilder
{
try
{
// we need a loaded client world in order to
// get the textures for blocks
if (mc.getClientWorld() == null)
return;
DimensionType dim = world.dimensionType();
LodDimension lodDim;
int playerPosX;
int playerPosZ;
if (MinecraftWrapper.INSTANCE.getPlayer() == null)
if (mc.getPlayer() == null)
{
playerPosX = chunk.getPos().getMinBlockX();
playerPosZ = chunk.getPos().getMinBlockZ();
} else
{
playerPosX = (int) MinecraftWrapper.INSTANCE.getPlayer().getX();
playerPosZ = (int) MinecraftWrapper.INSTANCE.getPlayer().getZ();
playerPosX = (int) mc.getPlayer().getX();
playerPosZ = (int) mc.getPlayer().getZ();
}
if (lodWorld.getLodDimension(dim) == null)
{
@@ -181,10 +198,6 @@ public class LodBuilder
int startZ;
int endX;
int endZ;
int color;
byte light;
short height;
short depth;
try
{
LodDetail detail;
@@ -228,7 +241,7 @@ public class LodBuilder
case MULTI_LOD:
long[][] dataToMergeVertical;
dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data = DataPointUtil.mergeVerticalData(dataToMergeVertical);
data = DataPointUtil.mergeMultiData(dataToMergeVertical);
if (data.length == 0 || data == null)
data = new long[]{DataPointUtil.EMPTY_DATA};
lodDim.addData(detailLevel,
@@ -269,7 +282,7 @@ public class LodBuilder
int xAbs;
int yAbs;
int zAbs;
boolean hasCeiling = MinecraftWrapper.INSTANCE.getWorld().dimensionType().hasCeiling();
boolean hasCeiling = mc.getClientWorld().dimensionType().hasCeiling();
BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0);
int index = 0;
@@ -582,12 +595,12 @@ public class LodBuilder
{
int skyLight;
int blockLight;
if (MinecraftWrapper.INSTANCE.getPlayer() == null)
if (mc.getPlayer() == null)
return 0;
if (MinecraftWrapper.INSTANCE.getPlayer().level == null)
if (mc.getPlayer().level == null)
return 0;
IWorld world = MinecraftWrapper.INSTANCE.getPlayer().level;
IWorld world = mc.getPlayer().level;
blockLight = world.getBrightness(LightType.BLOCK, blockPos);
skyLight = world.getBrightness(LightType.SKY, blockPos);
@@ -610,23 +623,23 @@ public class LodBuilder
return colorMap.get(blockState.getBlock());
World world = MinecraftWrapper.INSTANCE.getWorld();
World world = mc.getClientWorld();
TextureAtlasSprite texture;
if(topTextureRequired)
{
List<BakedQuad> quad = ((IForgeBakedModel) MinecraftWrapper.INSTANCE.getModelManager().getBlockModelShaper().getBlockModel(blockState)).getQuads(blockState, Direction.UP, new Random(0), dataMap);
List<BakedQuad> quad = ((IForgeBakedModel) mc.getModelManager().getBlockModelShaper().getBlockModel(blockState)).getQuads(blockState, Direction.UP, new Random(0), dataMap);
if (!quad.isEmpty())
{
texture = quad.get(0).getSprite();
}
else
{
texture = MinecraftWrapper.INSTANCE.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos);
texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos);
}
}
else
{
texture = MinecraftWrapper.INSTANCE.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos);
texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos);
}
@@ -688,15 +701,13 @@ public class LodBuilder
int z = blockPos.getZ();
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2);
int brightness;
int red = 0;
int green = 0;
int blue = 0;
BlockState blockState = chunk.getBlockState(blockPos);
int colorInt = 0;
// block special cases
// TODO: this needs to be replaced by a config file of some sort
if (blockState == Blocks.AIR.defaultBlockState()
|| blockState == Blocks.CAVE_AIR.defaultBlockState()
|| blockState == Blocks.BARRIER.defaultBlockState())
@@ -720,7 +731,7 @@ public class LodBuilder
{
colorInt = Blocks.NETHER_WART_BLOCK.defaultMaterialColor().col;
} else if (blockState.getBlock().equals(Blocks.TWISTING_VINES)
|| blockState.equals(Blocks.TWISTING_VINES_PLANT)
|| blockState.equals(Blocks.TWISTING_VINES_PLANT.defaultBlockState())
|| blockState == Blocks.WARPED_ROOTS.defaultBlockState()
|| blockState == Blocks.WARPED_FUNGUS.defaultBlockState()
|| blockState == Blocks.NETHER_SPROUTS.defaultBlockState())
@@ -17,13 +17,15 @@
*/
package com.seibel.lod.builders.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.util.ColorUtil;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.DimensionType;
/**
* This is the abstract class used to create different
@@ -36,7 +38,7 @@ public abstract class AbstractLodTemplate
{
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, NativeImage lightMap);
/**
@@ -44,10 +46,10 @@ public abstract class AbstractLodTemplate
*/
protected void addPosAndColor(BufferBuilder buffer,
double x, double y, double z,
int red, int green, int blue, int alpha)
int color)
{
buffer.vertex(x, y, z).color(red, green, blue, alpha).endVertex();
buffer.vertex(x, y, z).color(ColorUtil.getRed(color), ColorUtil.getGreen(color), ColorUtil.getBlue(color), ColorUtil.getAlpha(color)).endVertex();
}
/**
@@ -1,13 +1,19 @@
package com.seibel.lod.builders.lodTemplates;
import java.util.HashMap;
import java.util.Map;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.util.Direction;
import net.minecraft.util.math.vector.Vector3d;
public class Box
{
public static final int DOWN = 0;
public static final int UP = 1;
public static final int EAST = 2;
public static final int WEST = 3;
public static final int SOUTH = 4;
public static final int NORTH = 5;
public static final int OFFSET = 0;
public static final int WIDTH = 1;
@@ -16,49 +22,404 @@ public class Box
public static final int Y = 1;
public static final int Z = 2;
public static final int MIN = 0;
public static final int MAX = 1;
public static final int VOID_FACE = 0;
public static final Direction[] DIRECTIONS = new Direction[]{
Direction.UP,
Direction.DOWN,
Direction.WEST,
Direction.EAST,
Direction.NORTH,
Direction.SOUTH};
public static final Direction[] ADJ_DIRECTIONS = new Direction[]{
Direction.EAST,
Direction.WEST,
Direction.SOUTH,
Direction.NORTH};
@SuppressWarnings("serial")
public static final Map<Direction, int[][]> DIRECTION_VERTEX_MAP = new HashMap<Direction, int[][]>()
{{
put(Direction.UP, new int[][]{
{0, 1, 0},
{0, 1, 1},
{1, 1, 1},
{1, 1, 0}});
put(Direction.DOWN, new int[][]{
{1, 0, 0},
{1, 0, 1},
{0, 0, 1},
{0, 0, 0}});
put(Direction.EAST, new int[][]{
{1, 1, 0},
{1, 1, 1},
{1, 0, 1},
{1, 0, 0}});
put(Direction.WEST, new int[][]{
{0, 0, 0},
{0, 0, 1},
{0, 1, 1},
{0, 1, 0}});
put(Direction.SOUTH, new int[][]{
{1, 0, 1},
{1, 1, 1},
{0, 1, 1},
{0, 0, 1}});
put(Direction.NORTH, new int[][]{
{0, 0, 0},
{0, 1, 0},
{1, 1, 0},
{1, 0, 0}});
}};
@SuppressWarnings("serial")
public static final Map<Direction, int[]> FACE_DIRECTION = new HashMap<Direction, int[]>()
{{
put(Direction.UP, new int[]{Y, MAX});
put(Direction.DOWN, new int[]{Y, MIN});
put(Direction.EAST, new int[]{X, MAX});
put(Direction.WEST, new int[]{X, MIN});
put(Direction.SOUTH, new int[]{Z, MAX});
put(Direction.NORTH, new int[]{Z, MIN});
}};
@SuppressWarnings("serial")
public static final Map<Direction, int[]> DIRECTION_NORMAL_MAP = new HashMap<Direction, int[]>()
{{
put(Direction.UP, new int[]{0, 1, 0});
put(Direction.DOWN, new int[]{0, -1, 0});
put(Direction.EAST, new int[]{1, 0, 0});
put(Direction.WEST, new int[]{-1, 0, 0});
put(Direction.SOUTH, new int[]{0, 0, 1});
put(Direction.NORTH, new int[]{0, 0, -1});
}};
public int[][] box;
public Map<Direction, int[]> colorMap;
public int color;
public Map<Direction, int[][]> adjHeightAndDepth;
public Map<Direction, boolean[]> culling;
public Box(){
@SuppressWarnings("serial")
public Box()
{
box = new int[2][3];
//order = new long[32];
colorMap = new HashMap<Direction, int[]>()
{{
put(Direction.UP, new int[1]);
put(Direction.DOWN, new int[1]);
put(Direction.EAST, new int[1]);
put(Direction.WEST, new int[1]);
put(Direction.SOUTH, new int[1]);
put(Direction.NORTH, new int[1]);
}};
adjHeightAndDepth = new HashMap<Direction, int[][]>()
{{
put(Direction.EAST, new int[32][2]);
put(Direction.WEST, new int[32][2]);
put(Direction.SOUTH, new int[32][2]);
put(Direction.NORTH, new int[32][2]);
}};
culling = new HashMap<Direction, boolean[]>()
{{
put(Direction.UP, new boolean[1]);
put(Direction.DOWN, new boolean[1]);
put(Direction.EAST, new boolean[1]);
put(Direction.WEST, new boolean[1]);
put(Direction.SOUTH, new boolean[1]);
put(Direction.NORTH, new boolean[1]);
}};
}
public void set(int xWidth, int yWidth, int zWidth){
box[OFFSET][X] = 0;
box[OFFSET][Y] = 0;
box[OFFSET][Z] = 0;
box[WIDTH][X] = xWidth;
box[WIDTH][Y] = yWidth;
box[WIDTH][Z] = zWidth;
public void setColor(int color)
{
this.color = color;
for (Direction direction : DIRECTIONS)
{
colorMap.get(direction)[0] = ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientWorld().getShade(direction, true));
}
}
public void move(int xOffset, int yOffset, int zOffset){
public int getColor(Direction direction)
{
if (LodConfig.CLIENT.debugging.debugMode.get() != DebugMode.SHOW_DETAIL)
{
return colorMap.get(direction)[0];
} else
{
return color;
}
}
public void reset()
{
for (int i = 0; i < box.length; i++)
{
for (int j = 0; j < box[i].length; j++)
{
box[i][j] = 0;
}
}
for (Direction direction : DIRECTIONS)
{
colorMap.get(direction)[0] = 0;
}
for (Direction direction : ADJ_DIRECTIONS)
{
if(isCulled(direction)){
continue;
}
for (int i = 0; i < adjHeightAndDepth.get(direction).length; i++)
{
adjHeightAndDepth.get(direction)[i][0] = VOID_FACE;
adjHeightAndDepth.get(direction)[i][1] = VOID_FACE;
}
}
}
public void setUpCulling(int cullingDistance)
{
Vector3d playerPos = MinecraftWrapper.INSTANCE.getPlayer().position();
for (Direction direction : DIRECTIONS)
{
if(direction == Direction.DOWN)
culling.get(direction)[0] = playerPos.get(direction.getAxis()) > getFacePos(direction) + cullingDistance;
else if(direction == Direction.UP)
culling.get(direction)[0] = playerPos.get(direction.getAxis()) < getFacePos(direction) - cullingDistance;
else if(direction == Direction.WEST)
culling.get(direction)[0] = -playerPos.get(direction.getAxis()) > getFacePos(direction) + cullingDistance;
else if(direction == Direction.NORTH)
culling.get(direction)[0] = -playerPos.get(direction.getAxis()) > getFacePos(direction) + cullingDistance;
else if(direction == Direction.EAST)
culling.get(direction)[0] = -playerPos.get(direction.getAxis()) < getFacePos(direction) - cullingDistance;
else if(direction == Direction.SOUTH)
culling.get(direction)[0] = -playerPos.get(direction.getAxis()) < getFacePos(direction) - cullingDistance;
}
}
public boolean isCulled(Direction direction)
{
return culling.get(direction)[0];
}
public void setAdjData(Map<Direction, long[]> adjData)
{
int height;
int depth;
int minY = getMinY();
int maxY = getMaxY();
for (Direction direction : ADJ_DIRECTIONS)
{
//if(isCulled(direction)){
// continue;
//}
long[] dataPoint = adjData.get(direction);
if (dataPoint == null || DataPointUtil.isItVoid(dataPoint[0]))
{
adjHeightAndDepth.get(direction)[0][0] = maxY;
adjHeightAndDepth.get(direction)[0][1] = minY;
adjHeightAndDepth.get(direction)[1][0] = VOID_FACE;
adjHeightAndDepth.get(direction)[1][1] = VOID_FACE;
continue;
}
//We order the adj list
/**TODO remove this if the order is maintained naturally*/
/*
order[0] = 0;
for (int i = 0; i < dataPoint.length; i++)
{
int j = i - 1;
while (j >= 0 && DataPointUtil.getHeight(order[j]) > DataPointUtil.getHeight(dataPoint[i])) {
order[j + 1] = order[j];
j = j - 1;
}
order[j + 1] = dataPoint[i];
}*/
int i;
int faceToDraw = 0;
boolean firstFace = true;
boolean toFinish = false;
for (i = dataPoint.length - 1; i >= 0; i--)
{
long singleDataPoint = dataPoint[i];
height = DataPointUtil.getHeight(singleDataPoint);
depth = DataPointUtil.getDepth(singleDataPoint);
if (depth > maxY)
{//the adj data is higher than the current data
//we continue since there could be some other data that intersect the current
continue;
} else if (height < minY)
{//the adj data is lower than the current data
//we break since all the other data will be lower
if (firstFace)
{
adjHeightAndDepth.get(direction)[0][0] = getMaxY();
adjHeightAndDepth.get(direction)[0][1] = getMinY();
} else
{
adjHeightAndDepth.get(direction)[faceToDraw][1] = getMinY();
}
faceToDraw++;
toFinish = false;
break;
} else if (depth <= minY && height >= maxY)
{//the adj data contains the current
//we do not draw the face
adjHeightAndDepth.get(direction)[0][0] = VOID_FACE;
adjHeightAndDepth.get(direction)[0][1] = VOID_FACE;
break;
} else if (depth <= minY && height < maxY)
{//the adj data intersect the lower part of the current data
//if this is the only face we use the maxY and break
//if there was other face we finish the last one and break
if (firstFace)
{
adjHeightAndDepth.get(direction)[0][0] = getMaxY();
adjHeightAndDepth.get(direction)[0][1] = height;
} else
{
adjHeightAndDepth.get(direction)[faceToDraw][1] = height;
}
toFinish = false;
faceToDraw++;
break;
} else if (depth > minY && height >= maxY)
{//the adj data intersect the higher part of the current data
//we start the creation of a new face
adjHeightAndDepth.get(direction)[faceToDraw][0] = depth;
firstFace = false;
toFinish = true;
continue;
} else if (depth > minY && height < maxY)
{//the adj data is contained in the current data
if (firstFace)
{
adjHeightAndDepth.get(direction)[0][0] = getMaxY();
}
adjHeightAndDepth.get(direction)[faceToDraw][1] = height;
faceToDraw++;
adjHeightAndDepth.get(direction)[faceToDraw][0] = depth;
firstFace = false;
toFinish = true;
continue;
}
}
if (toFinish)
{
adjHeightAndDepth.get(direction)[faceToDraw][1] = minY;
faceToDraw++;
}
adjHeightAndDepth.get(direction)[faceToDraw][0] = VOID_FACE;
adjHeightAndDepth.get(direction)[faceToDraw][1] = VOID_FACE;
}
}
public void set(int xWidth, int yWidth, int zWidth)
{
box[WIDTH][X] = xWidth;
box[WIDTH][Y] = yWidth;
box[WIDTH][Z] = zWidth;
}
public void move(int xOffset, int yOffset, int zOffset)
{
box[OFFSET][X] = xOffset;
box[OFFSET][Y] = yOffset;
box[OFFSET][Z] = zOffset;
}
public int getMinX(){
public int getFacePos(Direction direction)
{
return box[OFFSET][FACE_DIRECTION.get(direction)[0]] + box[WIDTH][FACE_DIRECTION.get(direction)[0]] * FACE_DIRECTION.get(direction)[1];
}
public int getCoord(Direction direction, int axis, int vertexIndex)
{
return box[OFFSET][axis] + box[WIDTH][axis] * DIRECTION_VERTEX_MAP.get(direction)[vertexIndex][axis];
}
public int getX(Direction direction, int vertexIndex)
{
return box[OFFSET][X] + box[WIDTH][X] * DIRECTION_VERTEX_MAP.get(direction)[vertexIndex][X];
}
public int getY(Direction direction, int vertexIndex)
{
return box[OFFSET][Y] + box[WIDTH][Y] * DIRECTION_VERTEX_MAP.get(direction)[vertexIndex][Y];
}
public int getY(Direction direction, int vertexIndex, int adjIndex)
{
if (direction == Direction.DOWN || direction == Direction.UP)
{
return box[OFFSET][Y] + box[WIDTH][Y] * DIRECTION_VERTEX_MAP.get(direction)[vertexIndex][Y];
} else
{
return adjHeightAndDepth.get(direction)[adjIndex][1 - DIRECTION_VERTEX_MAP.get(direction)[vertexIndex][Y]];
}
}
public int getZ(Direction direction, int vertexIndex)
{
return box[OFFSET][Z] + box[WIDTH][Z] * DIRECTION_VERTEX_MAP.get(direction)[vertexIndex][Z];
}
public boolean shouldContinue(Direction direction, int adjIndex)
{
if (direction == Direction.UP || direction == Direction.DOWN)
{
if (adjIndex == 0)
return true;
else
return false;
}
return !(adjHeightAndDepth.get(direction)[adjIndex][0] == VOID_FACE && adjHeightAndDepth.get(direction)[adjIndex][1] == VOID_FACE);
}
public int getMinX()
{
return box[OFFSET][X];
}
public int getMaxX(){
public int getMaxX()
{
return box[OFFSET][X] + box[WIDTH][X];
}
public int getMinY(){
public int getMinY()
{
return box[OFFSET][Y];
}
public int getMaxY(){
public int getMaxY()
{
return box[OFFSET][Y] + box[WIDTH][Y];
}
public int getMinZ(){
public int getMinZ()
{
return box[OFFSET][Z];
}
public int getMaxZ(){
public int getMaxZ()
{
return box[OFFSET][Z] + box[WIDTH][Z];
}
}
@@ -17,24 +17,16 @@
*/
package com.seibel.lod.builders.lodTemplates;
import com.seibel.lod.config.LodConfig;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.enums.ShadingMode;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.DimensionType;
import java.lang.annotation.Native;
/**
* Builds LODs as rectangular prisms.
@@ -44,20 +36,27 @@ import java.lang.annotation.Native;
*/
public class CubicLodTemplate extends AbstractLodTemplate
{
private final int CULL_OFFSET = 16;
public CubicLodTemplate()
{
}
@Override
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, NativeImage lightMap)
{
int width = 1 << detailLevel;
int color = DataPointUtil.getLightColor(data, lightMap);
// add each LOD for the detail level
if (debugging != DebugMode.OFF)
{
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
}
generateBoundingBox(
box,
DataPointUtil.getHeight(data),
@@ -66,28 +65,19 @@ public class CubicLodTemplate extends AbstractLodTemplate
posX * width,
0,
posZ * width,
bufferCenterBlockPos);
int color;
color = DataPointUtil.getLightColor(data,lightMap);
//color = DataPointUtil.getColor(data);
if (debugging != DebugMode.OFF)
{
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
}
bufferCenterBlockPos,
adjData,
color);
if (box != null)
{
addBoundingBoxToBuffer(buffer, box, color, bufferCenterBlockPos, adjData);
addBoundingBoxToBuffer(buffer, box);
}
}
private void generateBoundingBox(Box box, int height, int depth, int width, double xOffset, double yOffset, double zOffset, BlockPos bufferCenterBlockPos)
private void generateBoundingBox(Box box, int height, int depth, int width, double xOffset, double yOffset, double zOffset, BlockPos bufferCenterBlockPos, Map<Direction, long[]> adjData, int color)
{
// don't add an LOD if it is empty
if (height == -1 && depth == -1)
@@ -105,285 +95,34 @@ public class CubicLodTemplate extends AbstractLodTemplate
// which only uses floats
double x = -bufferCenterBlockPos.getX();
double z = -bufferCenterBlockPos.getZ();
box.reset();
box.setColor(color);
box.set(width, height - depth, width);
box.move((int) (xOffset + x), (int) (yOffset + depth), (int) (zOffset + z));
box.move((int) (xOffset + x), (int) (depth + yOffset), (int) (zOffset + z));
box.setUpCulling(32);
box.setAdjData(adjData);
}
private void addBoundingBoxToBuffer(BufferBuilder buffer, Box box, int c, BlockPos playerBlockPos, long[] adjData)
private void addBoundingBoxToBuffer(BufferBuilder buffer, Box box)
{
int topColor = c;
int bottomColor = c;
int northColor = c;
int southColor = c;
int westColor = c;
int eastColor = c;
// darken the bottom and side colors if requested
if (LodConfig.CLIENT.graphics.shadingMode.get() == ShadingMode.DARKEN_SIDES)
for(Direction direction : Box.DIRECTIONS)
{
// the side colors are different because
// when using fast lighting in Minecraft the north/south
// and east/west sides are different in a similar way
/**TODO OPTIMIZE THIS STEP*/
Minecraft mc = Minecraft.getInstance();
topColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.UP, true));
bottomColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.DOWN, true));
northColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.NORTH, true));
southColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.SOUTH, true));
westColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.WEST, true));
eastColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.EAST, true));
}
// apply the user specified saturation and brightness
float saturationMultiplier = LodConfig.CLIENT.graphics.saturationMultiplier.get().floatValue();
float brightnessMultiplier = LodConfig.CLIENT.graphics.brightnessMultiplier.get().floatValue();
if (saturationMultiplier != 1 || brightnessMultiplier != 1)
{
topColor = ColorUtil.applySaturationAndBrightnessMultipliers(topColor, saturationMultiplier, brightnessMultiplier);
bottomColor = ColorUtil.applySaturationAndBrightnessMultipliers(bottomColor, saturationMultiplier, brightnessMultiplier);
northColor = ColorUtil.applySaturationAndBrightnessMultipliers(northColor, saturationMultiplier, brightnessMultiplier);
southColor = ColorUtil.applySaturationAndBrightnessMultipliers(southColor, saturationMultiplier, brightnessMultiplier);
westColor = ColorUtil.applySaturationAndBrightnessMultipliers(westColor, saturationMultiplier, brightnessMultiplier);
eastColor = ColorUtil.applySaturationAndBrightnessMultipliers(eastColor, saturationMultiplier, brightnessMultiplier);
}
int minX;
int maxX;
int minY;
int maxY;
int minZ;
int maxZ;
long data;
int tempMinY;
int tempMaxY;
int red;
int green;
int blue;
int alpha;
boolean disableCulling = true;
/**TODO make all of this more automatic if possible*/
if (playerBlockPos.getY() > box.getMaxY() - CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(topColor);
green = ColorUtil.getGreen(topColor);
blue = ColorUtil.getBlue(topColor);
alpha = ColorUtil.getAlpha(topColor);
// top (facing up)
minX = box.getMinX();
maxX = box.getMaxX();
minY = box.getMinY();
maxY = box.getMaxY();
minZ = box.getMinZ();
maxZ = box.getMaxZ();
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
}
if (playerBlockPos.getY() < box.getMinY() + CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(bottomColor);
green = ColorUtil.getGreen(bottomColor);
blue = ColorUtil.getBlue(bottomColor);
alpha = ColorUtil.getAlpha(bottomColor);
// bottom (facing down)
minX = box.getMinX();
maxX = box.getMaxX();
minY = box.getMinY();
maxY = box.getMaxY();
minZ = box.getMinZ();
maxZ = box.getMaxZ();
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
}
if (playerBlockPos.getX() < box.getMaxX() + CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(westColor);
green = ColorUtil.getGreen(westColor);
blue = ColorUtil.getBlue(westColor);
alpha = ColorUtil.getAlpha(westColor);
// west (facing -X)
data = adjData[0];
minX = box.getMinX();
maxX = box.getMaxX();
minY = box.getMinY();
maxY = box.getMaxY();
minZ = box.getMinZ();
maxZ = box.getMaxZ();
if (data == 0)
//if(box.isCulled(direction))
// continue;
int adjIndex = 0;
while(box.shouldContinue(direction, adjIndex))
{
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
}else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++)
{
minY = Math.max(tempMaxY, minY);
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
}
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
maxY = Math.min(tempMinY, maxY);
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer,
box.getX(direction, vertexIndex),
box.getY(direction, vertexIndex, adjIndex),
box.getZ(direction, vertexIndex),
box.getColor(direction));
}
adjIndex++;
}
}
if (playerBlockPos.getX() > box.getMinX() - CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(eastColor);
green = ColorUtil.getGreen(eastColor);
blue = ColorUtil.getBlue(eastColor);
alpha = ColorUtil.getAlpha(eastColor);
// east (facing +X)
data = adjData[1];
minX = box.getMinX();
maxX = box.getMaxX();
minY = box.getMinY();
maxY = box.getMaxY();
minZ = box.getMinZ();
maxZ = box.getMaxZ();
if (data == 0)
{
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
maxY = Math.min(tempMinY, maxY);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
}
}
if (playerBlockPos.getZ() > box.getMinZ() - CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(northColor);
green = ColorUtil.getGreen(northColor);
blue = ColorUtil.getBlue(northColor);
alpha = ColorUtil.getAlpha(northColor);
data = adjData[3];
minX = box.getMinX();
maxX = box.getMaxX();
minY = box.getMinY();
maxY = box.getMaxY();
minZ = box.getMinZ();
maxZ = box.getMaxZ();
// north (facing +Z)
if (data == 0)
{
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
}
else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
}
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
maxY = Math.min(tempMinY, maxY);
addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha);
}
}
}
if (playerBlockPos.getZ() < box.getMaxZ() + CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(southColor);
green = ColorUtil.getGreen(southColor);
blue = ColorUtil.getBlue(southColor);
alpha = ColorUtil.getAlpha(southColor);
data = adjData[2];
minX = box.getMinX();
maxX = box.getMaxX();
minY = box.getMinY();
maxY = box.getMaxY();
minZ = box.getMinZ();
maxZ = box.getMaxZ();
// south (facing -Z)
if (data == 0)
{
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
else
{
maxY = box.getMaxY();
tempMaxY = DataPointUtil.getHeight(data);
if (tempMaxY < maxY)
{
minY = Math.max(tempMaxY, minY);
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
tempMinY = DataPointUtil.getDepth(data);
minY = box.getMinY();
if (tempMinY > minY)
{
maxY = Math.min(tempMinY, maxY);
addPosAndColor(buffer, minX, minY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha);
addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha);
}
}
}
}
@Override
@@ -17,12 +17,15 @@
*/
package com.seibel.lod.builders.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.proxy.ClientProxy;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.DimensionType;
/**
* TODO DynamicLodTemplate
@@ -36,10 +39,10 @@ import net.minecraft.world.DimensionType;
public class DynamicLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, NativeImage lightMap)
{
System.err.println("DynamicLodTemplate not implemented!");
ClientProxy.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
}
@Override
@@ -17,12 +17,15 @@
*/
package com.seibel.lod.builders.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.proxy.ClientProxy;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.DimensionType;
/**
* TODO #21 TriangularLodTemplate
@@ -34,10 +37,10 @@ import net.minecraft.world.DimensionType;
public class TriangularLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, NativeImage lightMap)
{
System.err.println("DynamicLodTemplate not implemented!");
ClientProxy.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
}
@Override
@@ -24,7 +24,6 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.function.Supplier;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
@@ -20,13 +20,21 @@ package com.seibel.lod.config;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.seibel.lod.enums.*;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.io.WritingMode;
import com.seibel.lod.ModInfo;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.enums.DistanceCalculatorType;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogDrawOverride;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.enums.LodTemplate;
import com.seibel.lod.enums.ShadingMode;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -37,7 +45,7 @@ import net.minecraftforge.fml.config.ModConfig;
* This handles any configuration the user has access to.
*
* @author James Seibel
* @version 9-1-2021
* @version 9-17-2021
*/
@Mod.EventBusSubscriber
public class LodConfig
@@ -87,6 +95,8 @@ public class LodConfig
public ForgeConfigSpec.IntValue lodChunkRenderDistance;
public ForgeConfigSpec.BooleanValue disableDirectionalCulling;
public ForgeConfigSpec.DoubleValue brightnessMultiplier;
public ForgeConfigSpec.DoubleValue saturationMultiplier;
@@ -150,6 +160,18 @@ public class LodConfig
+ " This is the render distance of the mod \n")
.defineInRange("lodChunkRenderDistance", 64, 32, 512);
disableDirectionalCulling = builder
.comment("\n\n"
+ " If false LODs that are behind the player's camera \n"
+ " aren't drawn, increasing performance. \n\n"
+ ""
+ " If true all LODs are drawn, even those behind \n"
+ " the player's camera, decreasing performance. \n\n"
+ ""
+ " Disable this if you see LODs disapearing. \n"
+ " (This may happen if you are using a camera mod) \n")
.define("disableDirectionalCulling", false);
shadingMode = builder
.comment("\n\n"
+ " What kind of shading should the LODs have? \n"
@@ -17,7 +17,14 @@
*/
package com.seibel.lod.handlers;
import java.io.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.ExecutorService;
@@ -25,7 +32,10 @@ import java.util.concurrent.Executors;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.objects.*;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.objects.SingleLevelContainer;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
@@ -212,10 +222,10 @@ public class LodDimensionFileHandler
{
for (int j = 0; j < loadedDimension.getWidth(); j++)
{
if (loadedDimension.isRegionDirty[i][j] && loadedDimension.regions[i][j] != null)
if (loadedDimension.getRegenByArrayIndex(i,j) && loadedDimension.getRegionByArrayIndex(i,j) != null)
{
saveRegionToFile(loadedDimension.regions[i][j]);
loadedDimension.isRegionDirty[i][j] = false;
saveRegionToFile(loadedDimension.getRegionByArrayIndex(i,j));
loadedDimension.setRegenByArrayIndex(i, j,false);
}
}
}
@@ -26,7 +26,11 @@ import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.handlers.LodDimensionFileHandler;
import com.seibel.lod.util.*;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.util.math.ChunkPos;
@@ -41,13 +45,13 @@ import net.minecraft.world.server.ServerWorld;
*
* @author Leonardo Amato
* @author James Seibel
* @version 8-8-2021
* @version 9-18-2021
*/
public class LodDimension
{
public final DimensionType dimension;
/**
* measured in regions
*/
@@ -56,23 +60,28 @@ public class LodDimension
* measured in regions
*/
private volatile int halfWidth;
public volatile LodRegion regions[][];
public volatile boolean isRegionDirty[][];
public volatile boolean regen[][];
// these three variables are private to force use of the getWidth() method
// which is a safer way to get the width then directly asking the arrays
/** stores all the regions in this dimension */
private volatile LodRegion regions[][];
/** stores if the region at the given x and z index needs to be saved to disk */
private volatile boolean isRegionDirty[][];
/** stores if the region at the given x and z index needs to be regenerated */
private volatile boolean regionNeedsRegen[][];
/**
* if true that means there are regions in this dimension
* that need to have their buffers rebuilt.
*/
public volatile boolean regenDimension = false;
private volatile RegionPos center;
private volatile ChunkPos lastGenChunk;
private volatile ChunkPos lastCutChunk;
private LodDimensionFileHandler fileHandler;
private ExecutorService cutAndGenThreads = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - cutAndGen"));
/**
* Creates the dimension centered at (0,0)
*
@@ -90,14 +99,14 @@ public class LodDimension
{
try
{
File saveDir;
if (mc.hasSingleplayerServer())
{
// local world
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension);
// provider needs a separate variable to prevent
// the compiler from complaining
ServerChunkProvider provider = serverWorld.getChunkSource();
@@ -105,11 +114,11 @@ public class LodDimension
} else
{
// connected to server
saveDir = new File(mc.getGameDirectory().getCanonicalFile().getPath() +
File.separatorChar + "lod server data" + File.separatorChar + mc.getCurrentDimensionId());
File.separatorChar + "lod server data" + File.separatorChar + mc.getCurrentDimensionId());
}
fileHandler = new LodDimensionFileHandler(saveDir, this);
} catch (IOException e)
{
@@ -117,23 +126,23 @@ public class LodDimension
// we won't be able to read or write any files
}
}
regions = new LodRegion[width][width];
isRegionDirty = new boolean[width][width];
regen = new boolean[width][width];
regionNeedsRegen = new boolean[width][width];
//treeGenerator((int) mc.player.getX(),(int) mc.player.getZ());
// populate isRegionDirty
for (int i = 0; i < width; i++)
for (int j = 0; j < width; j++)
isRegionDirty[i][j] = false;
center = new RegionPos(0, 0);
}
/**
* Move the center of this LodDimension and move all owned
* regions over by the given x and z offset. <br><br>
@@ -144,7 +153,7 @@ public class LodDimension
{
int xOffset = regionOffset.x;
int zOffset = regionOffset.z;
// if the x or z offset is equal to or greater than
// the total size, just delete the current data
// and update the centerX and/or centerZ
@@ -157,15 +166,15 @@ public class LodDimension
regions[x][z] = null;
}
}
// update the new center
center.x += xOffset;
center.z += zOffset;
return;
}
// X
if (xOffset > 0)
{
@@ -196,8 +205,8 @@ public class LodDimension
}
}
}
// Z
if (zOffset > 0)
{
@@ -226,22 +235,22 @@ public class LodDimension
}
}
}
// update the new center
center.x += xOffset;
center.z += zOffset;
}
/**
* return needed memory in byte
* return needed memory in bytes
*/
public int getMinMemoryNeeded()
{
int count = 0;
LodRegion region;
for (int x = 0; x < regions.length; x++)
{
for (int z = 0; z < regions.length; z++)
@@ -255,8 +264,8 @@ public class LodDimension
}
return count;
}
/**
* Gets the region at the given X and Z
* <br>
@@ -269,19 +278,19 @@ public class LodDimension
int zRegion = LevelPosUtil.getRegion(detailLevel, posZ);
int xIndex = (xRegion - center.x) + halfWidth;
int zIndex = (zRegion - center.z) + halfWidth;
if (!regionIsInRange(xRegion, zRegion))
return null;
//throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range");
//throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range");
else if (regions[xIndex][zIndex] == null)
return null;
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " not currently initialized");
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " not currently initialized");
else if (regions[xIndex][zIndex].getMinDetailLevel() > detailLevel)
return null;
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " currently only reach level " + regions[xIndex][zIndex].getMinDetailLevel());
return regions[xIndex][zIndex];
}
/**
* Gets the region at the given X and Z
* <br>
@@ -292,16 +301,22 @@ public class LodDimension
{
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
if (!regionIsInRange(regionPosX, regionPosZ))
return null;
//throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range");
//throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range");
else if (regions[xIndex][zIndex] == null)
return null;
//throw new InvalidParameterException("Region " + regionPosX + " " + regionPosZ + " not currently initialized");
return regions[xIndex][zIndex];
}
/** Useful when needing to iterate over every region. */
public LodRegion getRegionByArrayIndex(int xIndex, int zIndex)
{
return regions[xIndex][zIndex];
}
/**
* Overwrite the LodRegion at the location of newRegion with newRegion.
*
@@ -311,15 +326,15 @@ public class LodDimension
{
int xIndex = (newRegion.regionPosX - center.x) + halfWidth;
int zIndex = (newRegion.regionPosZ - center.z) + halfWidth;
if (!regionIsInRange(newRegion.regionPosX, newRegion.regionPosZ))
// out of range
throw new ArrayIndexOutOfBoundsException("Region " + newRegion.regionPosX + ", " + newRegion.regionPosZ + " out of range");
regions[xIndex][zIndex] = newRegion;
}
/**
*
*/
@@ -338,7 +353,7 @@ public class LodDimension
int minDistance;
byte detail;
byte levelToCut;
for (int x = 0; x < regions.length; x++)
{
for (int z = 0; z < regions.length; z++)
@@ -358,15 +373,15 @@ public class LodDimension
regions[x][z].cutTree(levelToCut);
}
}
}// region z
}// region z
});
cutAndGenThreads.execute(thread);
}
}
/**
*
*/
@@ -375,7 +390,7 @@ public class LodDimension
DistanceGenerationMode generationMode = LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get();
ChunkPos newPlayerChunk = new ChunkPos(LevelPosUtil.getChunkPos((byte) 0, playerPosX), LevelPosUtil.getChunkPos((byte) 0, playerPosZ));
LodQualityMode lodQualityMode = LodConfig.CLIENT.worldGenerator.lodQualityMode.get();
if (lastGenChunk == null)
lastGenChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1);
if (newPlayerChunk.x != lastGenChunk.x || newPlayerChunk.z != lastGenChunk.z)
@@ -398,25 +413,25 @@ public class LodDimension
final RegionPos regionPos = new RegionPos(regionX, regionZ);
region = regions[x][z];
//We require that the region we are checking is loaded with at least this level
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ);
detail = DetailDistanceUtil.getDistanceTreeGenInverse(minDistance);
levelToGen = DetailDistanceUtil.getLodGenDetail(detail).detailLevel;
if (region == null || region.getGenerationMode() != generationMode)
{
//First case, region has to be initialized
//We check if there is a file at the target level
regions[x][z] = getRegionFromFile(regionPos, levelToGen, generationMode, lodQualityMode);
//if there is no file we initialize the region
if (regions[x][z] == null)
{
regions[x][z] = new LodRegion(levelToGen, regionPos, generationMode, lodQualityMode);
}
regen[x][z] = true;
regionNeedsRegen[x][z] = true;
regenDimension = true;
} else if (region.getMinDetailLevel() > levelToGen)
{
//Second case, region has been initialized but at a higher level
@@ -429,7 +444,7 @@ public class LodDimension
cutAndGenThreads.execute(thread);
}
}
/**
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
@@ -437,11 +452,11 @@ public class LodDimension
*/
public Boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
@@ -455,7 +470,7 @@ public class LodDimension
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
regen[xIndex][zIndex] = true;
regionNeedsRegen[xIndex][zIndex] = true;
regenDimension = true;
} catch (ArrayIndexOutOfBoundsException e)
{
@@ -466,8 +481,8 @@ public class LodDimension
}
return nodeAdded;
}
/**
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
@@ -475,11 +490,11 @@ public class LodDimension
*/
public Boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
@@ -493,7 +508,7 @@ public class LodDimension
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
regen[xIndex][zIndex] = true;
regionNeedsRegen[xIndex][zIndex] = true;
regenDimension = true;
} catch (ArrayIndexOutOfBoundsException e)
{
@@ -504,14 +519,14 @@ public class LodDimension
}
return nodeAdded;
}
public void setToRegen(int xRegion, int zRegion)
{
int xIndex = (xRegion - center.x) + halfWidth;
int zIndex = (zRegion - center.z) + halfWidth;
regen[xIndex][zIndex] = true;
regionNeedsRegen[xIndex][zIndex] = true;
}
/**
* method to get all the quadtree level that have to be generated based on the position of the player
*
@@ -533,12 +548,12 @@ public class LodDimension
region = getRegion(xIndex, zIndex);
if (region != null)
region.getDataToGenerate(posToGenerate, playerPosX, playerPosZ);
}
}
return posToGenerate;
}
/**
* method to get all the nodes that have to be rendered based on the position of the player
*
@@ -550,7 +565,7 @@ public class LodDimension
if (region != null)
region.getDataToRender(posToRender, playerPosX, playerPosZ);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
@@ -562,17 +577,17 @@ public class LodDimension
{
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 new long[]{DataPointUtil.EMPTY_DATA};
}
return region.getData(detailLevel, posX, posZ);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
@@ -584,17 +599,28 @@ public class LodDimension
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return DataPointUtil.EMPTY_DATA;
}
return region.getSingleData(detailLevel, posX, posZ);
}
public boolean getRegenByArrayIndex(int xIndex, int zIndex)
{
return regionNeedsRegen[xIndex][zIndex];
}
public void setRegenByArrayIndex(int xIndex, int zIndex, boolean newRegen)
{
regionNeedsRegen[xIndex][zIndex] = newRegen;
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
@@ -606,32 +632,32 @@ public class LodDimension
{
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;
}
region.updateArea(detailLevel, posX, posZ);
}
/**
* return true if and only if the node at that position exist
*/
public boolean doesDataExist(byte detailLevel, int posX, int posZ)
{
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return false;
}
return region.doesDataExist(detailLevel, posX, posZ);
}
/**
* Get the region at the given X and Z coordinates from the
* RegionFileHandler.
@@ -643,7 +669,7 @@ public class LodDimension
else
return null;
}
/**
* Save all dirty regions in this LodDimension to file.
*/
@@ -651,8 +677,8 @@ public class LodDimension
{
fileHandler.saveDirtyRegionsToFileAsync();
}
/**
* Returns whether the region at the given X and Z coordinates
* is within the loaded range.
@@ -661,22 +687,22 @@ public class LodDimension
{
int xIndex = (regionX - center.x) + halfWidth;
int zIndex = (regionZ - center.z) + halfWidth;
return xIndex >= 0 && xIndex < width && zIndex >= 0 && zIndex < width;
}
public int getCenterX()
{
return center.x;
}
public int getCenterZ()
{
return center.z;
}
/** returns the width of the dimension in regions */
public int getWidth()
{
if (regions != null)
@@ -690,28 +716,29 @@ public class LodDimension
return width;
}
}
public void setRegionWidth(int newWidth)
{
width = newWidth;
halfWidth = Math.floorDiv(width, 2);
regions = new LodRegion[width][width];
isRegionDirty = new boolean[width][width];
regen = new boolean[width][width];
regionNeedsRegen = new boolean[width][width];
// populate isRegionDirty
for (int i = 0; i < width; i++)
for (int j = 0; j < width; j++)
isRegionDirty[i][j] = false;
}
@Override
public String toString()
{
LodRegion region;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Dimension : \n");
for (int x = 0; x < regions.length; x++)
@@ -723,7 +750,7 @@ public class LodDimension
{
stringBuilder.append("n");
stringBuilder.append("\t");
} else
{
stringBuilder.append(region.getMinDetailLevel());
@@ -1,9 +1,9 @@
package com.seibel.lod.objects;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
@@ -15,8 +15,9 @@ import com.seibel.lod.util.LodUtil;
* if an array contain coordinate the order is the following
* 0 for x, 1 for z in 2D
* 0 for x, 1 for y, 2 for z in 3D
*
*
*/
public class LodRegion
{
//x coord,
@@ -82,7 +83,7 @@ public class LodRegion
* This method can be used to insert data into the LodRegion
*
* @param dataPoint
* @return
* @return if the data was added successfully
*/
public boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean serverQuality)
{
@@ -90,14 +91,25 @@ public class LodRegion
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (!doesDataExist(detailLevel, posX, posZ) || serverQuality)
{
//update the number of node present
//update the number of nodes present
//if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++;
//add the node data
this.dataContainer[detailLevel].addData(dataPoint, posX, posZ);
return true;
} else
try
{
//add the node data
this.dataContainer[detailLevel].addData(dataPoint, posX, posZ);
return true;
}
catch (NullPointerException e)
{
String detailMessage = "pos: [" + posX + "," + posZ + "] dataPoint: [" + dataPoint + "] serverQuality: [" + serverQuality + "] dataContainer";
detailMessage += this.dataContainer != null ? ": [NULL]" : " at detailLevel: [" + dataContainer[detailLevel] + "]";
ClientProxy.LOGGER.error("addSingleData: " + e.getMessage() + "\t" + detailMessage);
return false;
}
}
else
{
return false;
}
@@ -107,7 +119,7 @@ public class LodRegion
* This method can be used to insert data into the LodRegion
*
* @param dataPoint
* @return
* @return if the data was added successfully
*/
public boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean serverQuality)
{
@@ -115,14 +127,25 @@ public class LodRegion
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (!doesDataExist(detailLevel, posX, posZ) || serverQuality)
{
//update the number of node present
//update the number of nodes present
//if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++;
//add the node data
this.dataContainer[detailLevel].addSingleData(dataPoint, posX, posZ);
return true;
} else
try
{
//add the node data
this.dataContainer[detailLevel].addSingleData(dataPoint, posX, posZ);
return true;
}
catch (NullPointerException e)
{
String detailMessage = "pos: [" + posX + "," + posZ + "] dataPoint: [" + dataPoint + "] serverQuality: [" + serverQuality + "] dataContainer";
detailMessage += this.dataContainer != null ? ": [NULL]" : " at detailLevel: [" + dataContainer[detailLevel] + "]";
ClientProxy.LOGGER.error("addSingleData: " + e.getMessage() + "\t" + detailMessage);
return false;
}
}
else
{
return false;
}
@@ -1,8 +1,14 @@
package com.seibel.lod.objects;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
/**
*
* @author Leonardo Amato
* @version 9-18-2021
*/
public class PosToRenderContainer
{
public byte minDetail;
@@ -26,6 +32,18 @@ public class PosToRenderContainer
public void addPosToRender(byte detailLevel, int posX, int posZ)
{
// When rapidly changing dimensions the bufferBuidler can cause this,
// James isn't sure why, but this will prevent an exception at
// the very least (while stilling logging the problem).
if (numberOfPosToRender >= posToRender.length)
{
// This is might be due to dimensions having a different width
// when first loading in
ClientProxy.LOGGER.error("Unable to addPosToRender. numberOfPosToRender [" + numberOfPosToRender +"] detailLevel [" + detailLevel + "] Pos [" + posX + "," + posZ + "]");
numberOfPosToRender++; // incrementing so we can see how many pos over the limit we would go
return;
}
//if(numberOfPosToRender >= posToRender.length)
// posToRender = Arrays.copyOf(posToRender, posToRender.length*2);
posToRender[numberOfPosToRender][0] = detailLevel;
@@ -110,7 +110,7 @@ public class VerticalLevelContainer implements LevelContainer
dataToMerge[2*z + x] = lowerLevelContainer.getData(childPosX, childPosZ);
}
}
data = DataPointUtil.mergeVerticalData(dataToMerge);
data = DataPointUtil.mergeMultiData(dataToMerge);
addData(data,posX,posZ);
}
@@ -128,7 +128,7 @@ public class GlProxy
}
if (!WGL.wglMakeCurrent(deviceContext, contextPointer))
throw new IllegalStateException("Unable to change OpenGL contexts! tried to change to [" + newContext.toString() + "] from [" + currentContext.toString() + "] lod builder owner thread: " + (lodBuilderOwnerThread != null ? lodBuilderOwnerThread.getName() : "null"));
throw new IllegalStateException("Unable to change OpenGL contexts! tried to change to [" + newContext.toString() + "] from [" + currentContext.toString() + "] on thread: [" + Thread.currentThread().getName() + "] lod builder owner thread: " + (lodBuilderOwnerThread != null ? lodBuilderOwnerThread.getName() : "null"));
if (newContext == GlProxyContext.LOD_BUILDER)
lodBuilderOwnerThread = Thread.currentThread();
@@ -23,7 +23,6 @@ import java.nio.FloatBuffer;
import java.util.HashSet;
import java.util.Iterator;
import net.minecraft.client.renderer.texture.NativeImage;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
@@ -53,6 +52,7 @@ import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.client.renderer.vertex.VertexFormat;
@@ -62,7 +62,6 @@ import net.minecraft.potion.Effects;
import net.minecraft.profiler.IProfiler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3f;
@@ -73,7 +72,7 @@ import net.minecraft.util.math.vector.Vector3f;
* This is where LODs are draw to the world.
*
* @author James Seibel
* @version 9-14-2021
* @version 9-18-2021
*/
public class LodRenderer
{
@@ -124,7 +123,10 @@ public class LodRenderer
* This is used to determine if the LODs should be regenerated
*/
private int[] previousPos = new int[]{0,0,0};
public NativeImage lightMap = null;
// these variables are used to determine if the buffers should be rebuilt
private long prevDayTime = 0;
private double prevBrightness = 0;
private int prevRenderDistance = 0;
@@ -245,15 +247,20 @@ public class LodRenderer
// get the default projection matrix so we can
// reset it after drawing the LODs
float[] defaultProjMatrix = new float[16];
GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, defaultProjMatrix);
float[] mcProjMatrixRaw = new float[16];
GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
Matrix4f mcProjectionMatrix = new Matrix4f(mcProjMatrixRaw);
// OpenGl outputs their matricies in col,row form instead of row,col
// (or maybe vice versa I have no idea :P)
mcProjectionMatrix.transpose();
Matrix4f modelViewMatrix = generateModelViewMatrix(partialTicks);
// required for setupFog and setupProjectionMatrix
farPlaneBlockDistance = LodConfig.CLIENT.graphics.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
setupProjectionMatrix(partialTicks);
setupProjectionMatrix(mcProjectionMatrix, partialTicks);
// commented out until we can add shaders to handle lighting
//setupLighting(lodDim, partialTicks);
NearFarFogSettings fogSettings = determineFogSettings();
@@ -278,6 +285,7 @@ public class LodRenderer
Vector3d cameraDir = cameraEntity.getLookAngle().normalize();
cameraDir = mc.getOptions().getCameraType().isMirrored() ? cameraDir.reverse() : cameraDir;
boolean cullingDisabled = LodConfig.CLIENT.graphics.disableDirectionalCulling.get();
// used to determine what type of fog to render
int halfWidth = vbos.length / 2;
@@ -288,7 +296,7 @@ public class LodRenderer
for (int j = 0; j < vbos.length; j++)
{
RegionPos vboPos = new RegionPos(i + lodDim.getCenterX() - lodDim.getWidth() / 2, j + lodDim.getCenterZ() - lodDim.getWidth() / 2);
if (RenderUtil.isRegionInViewFrustum(cameraEntity.blockPosition(), cameraDir, vboPos.blockPos()))
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(cameraEntity.blockPosition(), cameraDir, vboPos.blockPos()))
{
if ((i > halfWidth - quarterWidth && i < halfWidth + quarterWidth) && (j > halfWidth - quarterWidth && j < halfWidth + quarterWidth))
setupFog(fogSettings.near.distance, fogSettings.near.quality);
@@ -323,10 +331,8 @@ public class LodRenderer
// reset the projection matrix so anything drawn after
// the LODs will use the correct projection matrix
Matrix4f mvm = new Matrix4f(defaultProjMatrix);
mvm.transpose();
gameRender.resetProjectionMatrix(mvm);
gameRender.resetProjectionMatrix(mcProjectionMatrix);
// clear the depth buffer so anything drawn is drawn
// over the LODs
GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
@@ -495,69 +501,50 @@ public class LodRenderer
/**
* create a new projection matrix and send it over to the GPU
* <br><br>
* A lot of this code is copied from renderLevel (line 567)
* in the GameRender class. The code copied is anything with
* a matrixStack and is responsible for making sure the LOD
* objects distort correctly relative to the rest of the world.
* Distortions are caused by: standing in a nether portal,
* nausea potion effect, walking bobbing.
*
*
* @param currentProjectionMatrix this is Minecraft's current projection matrix
* @param partialTicks how many ticks into the frame we are
*/
private void setupProjectionMatrix(float partialTicks)
private void setupProjectionMatrix(Matrix4f currentProjectionMatrix, float partialTicks)
{
// Note: if the LOD objects don't distort correctly
// compared to regular minecraft terrain, make sure
// all the transformations in renderWorld are here too
MatrixStack matrixStack = new MatrixStack();
matrixStack.pushPose();
gameRender.bobHurt(matrixStack, partialTicks);
if (this.mc.getOptions().bobView)
{
gameRender.bobView(matrixStack, partialTicks);
}
// potion and nausea effects
float f = MathHelper.lerp(partialTicks, this.mc.getPlayer().oPortalTime, this.mc.getPlayer().portalTime) * this.mc.getOptions().screenEffectScale * this.mc.getOptions().screenEffectScale;
if (f > 0.0F)
{
int i = this.mc.getPlayer().hasEffect(Effects.CONFUSION) ? 7 : 20;
float f1 = 5.0F / (f * f + 5.0F) - f * 0.04F;
f1 = f1 * f1;
Vector3f vector3f = new Vector3f(0.0F, MathHelper.SQRT_OF_TWO / 2.0F, MathHelper.SQRT_OF_TWO / 2.0F);
matrixStack.mulPose(vector3f.rotationDegrees((gameRender.tick + partialTicks) * i));
matrixStack.scale(1.0F / f1, 1.0F, 1.0F);
float f2 = -(gameRender.tick + partialTicks) * i;
matrixStack.mulPose(vector3f.rotationDegrees(f2));
}
// this projection matrix allows us to see past the normal
// world render distance
Matrix4f projectionMatrix =
Matrix4f.perspective(
getFov(partialTicks, true),
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
// it is possible to see the near clip plane, but
// you have to be flying quickly in spectator mode through ungenerated
// terrain, so I don't think it is much of an issue.
mc.getRenderDistance()/2,
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH * 2);
// add the screen space distortions
projectionMatrix.multiply(matrixStack.last().pose());
gameRender.resetProjectionMatrix(projectionMatrix);
return;
// create the new projection matrix
Matrix4f lodPoj =
Matrix4f.perspective(
getFov(partialTicks, true),
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
mc.getRenderDistance()/2,
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH * 2 / 4);
// get Minecraft's un-edited projection matrix
// (this is before it is zoomed, distorted, etc.)
Matrix4f defaultMcProj = mc.getGameRenderer().getProjectionMatrix(mc.getGameRenderer().getMainCamera(), partialTicks, true);
// true here means use "use fov setting" (probably)
// this logic strips away the defaultMcProj matrix so we
// can get the distortionMatrix, which represents all
// transformations, zooming, distortions, etc. done
// to Minecraft's Projection matrix
Matrix4f defaultMcProjInv = defaultMcProj.copy();
defaultMcProjInv.invert();
Matrix4f distortionMatrix = defaultMcProjInv.copy();
distortionMatrix.multiply(currentProjectionMatrix);
// edit the lod projection to match Minecraft's
// (so the LODs line up with the real world)
lodPoj.multiply(distortionMatrix);
// send the projection over to the GPU
gameRender.resetProjectionMatrix(lodPoj);
}
/**
* setup the lighting to be used for the LODs
*/
@SuppressWarnings("deprecation")
@SuppressWarnings({ "deprecation", "unused" })
private void setupLighting(LodDimension lodDimension, float partialTicks)
{
// Determine if the player has night vision
@@ -782,7 +769,7 @@ public class LodRenderer
*/
private void determineIfLodsShouldRegenerate(LodDimension lodDim)
{
short renderDistance = (short) mc.getRenderDistance();
short chunkRenderDistance = (short) mc.getRenderDistance();
//=============//
// full regens //
@@ -799,7 +786,7 @@ public class LodRenderer
prevFogDistance = LodConfig.CLIENT.graphics.fogDistance.get();
prevRenderDistance = mc.getRenderDistance();
//should use this when it's ready
vanillaRenderedChunks = new boolean[renderDistance*2+2][renderDistance*2+2];
vanillaRenderedChunks = new boolean[chunkRenderDistance*2+2][chunkRenderDistance*2+2];
}
// did the user change the debug setting?
@@ -822,7 +809,7 @@ public class LodRenderer
fullRegen = true;
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
//should use this when it's ready
vanillaRenderedChunks = new boolean[renderDistance*2+2][renderDistance*2+2];
vanillaRenderedChunks = new boolean[chunkRenderDistance*2+2][chunkRenderDistance*2+2];
}
prevPlayerPosTime = newTime;
}
@@ -858,13 +845,13 @@ public class LodRenderer
prevChunkTime = newTime;
}
// check if there is any newly generated terrain to show
if (mc.getWorld().getDayTime() - prevDayTime > 1000 || mc.getOptions().gamma != prevBrightness || lightMap == null)
// check if the lighting has changed
if (mc.getClientWorld().getDayTime() - prevDayTime > 1000 || mc.getOptions().gamma != prevBrightness || lightMap == null)
{
fullRegen = true;
lightMap = mc.getCurrentLightMap();
prevBrightness = mc.getOptions().gamma;
prevDayTime = mc.getWorld().getDayTime();
prevDayTime = mc.getClientWorld().getDayTime();
}
@@ -876,23 +863,18 @@ public class LodRenderer
// determine which LODs should not be rendered close to the player
HashSet<ChunkPos> chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, mc.getPlayer().blockPosition());
int chunkX;
int chunkZ;
int xIndex;
int zIndex;
for (ChunkPos pos : chunkPosToSkip)
{
chunkX = pos.x - mc.getPlayer().xChunk + renderDistance + 1;
chunkZ = pos.z - mc.getPlayer().zChunk + renderDistance + 1;
try
xIndex = (pos.x - mc.getPlayer().xChunk) + chunkRenderDistance + 1;
zIndex = (pos.z - mc.getPlayer().zChunk) + chunkRenderDistance + 1;
if (!vanillaRenderedChunks[xIndex][zIndex])
{
if (!vanillaRenderedChunks[chunkX][chunkZ])
{
vanillaRenderedChunks[chunkX][chunkZ] = true;
vanillaRenderedChunksChanged = true;
lodDim.setToRegen(pos.getRegionX(), pos.getRegionZ());
}
}catch (Exception e){
System.out.println(vanillaRenderedChunks.length);
e.printStackTrace();
vanillaRenderedChunks[xIndex][zIndex] = true;
vanillaRenderedChunksChanged = true;
lodDim.setToRegen(pos.getRegionX(), pos.getRegionZ());
}
}
@@ -900,7 +882,7 @@ public class LodRenderer
// if the player is high enough, draw all LODs
if(chunkPosToSkip.isEmpty() && mc.getPlayer().position().y > 256)
{
vanillaRenderedChunks = new boolean[renderDistance*2+2][renderDistance*2+2];
vanillaRenderedChunks = new boolean[chunkRenderDistance*2+2][chunkRenderDistance*2+2];
vanillaRenderedChunksChanged = true;
}
}
@@ -1,12 +1,8 @@
package com.seibel.lod.util;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.NativeImage;
import javax.xml.crypto.Data;
import java.lang.annotation.Native;
import net.minecraft.client.renderer.texture.NativeImage;
public class DataPointUtil
{
@@ -171,8 +167,8 @@ public class DataPointUtil
public static int getColor(long dataPoint)
{
int color = getBlue(dataPoint) << BLUE_COLOR_SHIFT;
color += getRed(dataPoint) << BLUE_COLOR_SHIFT;
//int color = getBlue(dataPoint) << BLUE_COLOR_SHIFT;
//color += getRed(dataPoint) << BLUE_COLOR_SHIFT;
return (int) (dataPoint >>> COLOR_SHIFT);
}
@@ -220,7 +216,6 @@ public class DataPointUtil
public static long mergeSingleData(long[] dataToMerge)
{
int numberOfChildren = 0;
int numberOfVoidChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
@@ -281,7 +276,7 @@ public class DataPointUtil
}
}
public static long[] mergeVerticalData(long[][] dataToMerge)
public static long[] mergeMultiData(long[][] dataToMerge)
{
//new code
short[] projection = ThreadMapUtil.getProjectionShort((WORLD_HEIGHT + 1 ) >>> 4);
@@ -160,9 +160,9 @@ public class DetailDistanceUtil
public static byte getLodDrawDetail(int detail)
{
if (detail < minGenDetail)
if (detail < minDrawDetail)
{
return lodGenDetails[minGenDetail].detailLevel;
return lodGenDetails[minDrawDetail].detailLevel;
} else
{
return lodGenDetails[detail].detailLevel;
@@ -1,7 +1,5 @@
package com.seibel.lod.util;
import com.seibel.lod.util.LodUtil;
public class LevelPosUtil
{
public static int[] convert(int[] levelPos, byte newDetailLevel)
@@ -25,10 +25,9 @@ import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.wrappers.MinecraftWrapper;
import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.WorldRenderer.LocalRenderInformationContainer;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher.CompiledChunk;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
@@ -375,12 +374,12 @@ public class LodUtil
// go through every RenderInfo to get the compiled chunks
WorldRenderer renderer = mc.getLevelRenderer();
ObjectList<LocalRenderInformationContainer> chunks = renderer.renderChunks;
for (WorldRenderer.LocalRenderInformationContainer worldrenderer$localrenderinformationcontainer : chunks)
for (WorldRenderer.LocalRenderInformationContainer worldrenderer$localrenderinformationcontainer : renderer.renderChunks)
{
if (!worldrenderer$localrenderinformationcontainer.chunk.getCompiledChunk().hasNoRenderableLayers())
CompiledChunk compiledChunk = worldrenderer$localrenderinformationcontainer.chunk.getCompiledChunk();
if (!compiledChunk.hasNoRenderableLayers())
{
// add the ChunkPos for every empty compiled chunk
// add the ChunkPos for every rendered chunk
BlockPos bpos = worldrenderer$localrenderinformationcontainer.chunk.getOrigin();
loadedPos.add(new ChunkPos(bpos));
@@ -7,23 +7,23 @@ public class ThreadMapUtil
{
private static final int NUMBER_OF_DIRECTION = 4;
public static final ConcurrentMap<String, long[]> threadSingleAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadSingleGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadSingleUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[][]> threadBuilderArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[][][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadVerticalAddDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadVerticalGetDataMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[][]> threadVerticalUpdateMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, int[]> threadVerticalIndexesMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadSingleAddDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadSingleGetDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadSingleUpdateMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> threadBuilderArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadVerticalAddDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadVerticalGetDataMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[][]> threadVerticalUpdateMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[]> threadVerticalIndexesMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> threadAdjData = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> threadAdjData = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, boolean[]> projectionMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, short[]> projectionShortMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, int[][]> heightAndDepthMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap();
public static final ConcurrentMap<String, boolean[]> projectionMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, short[]> projectionShortMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, int[][]> heightAndDepthMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap<>();
public static long[] getSingleAddDataArray()
@@ -14,16 +14,14 @@ import net.minecraft.client.network.play.ClientPlayNetHandler;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.profiler.IProfiler;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.Direction;
import net.minecraft.world.DimensionType;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import org.lwjgl.system.CallbackI;
/**
* A singleton that wraps the Minecraft class
@@ -174,8 +172,8 @@ public class MinecraftWrapper
{
return mc.getModelManager();
}
public World getWorld()
public ClientWorld getClientWorld()
{
return mc.level;
}