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:
+4
-12
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user