Merge changes from 1.17.1-Forge (11-10-2021)
This commit is contained in:
@@ -56,23 +56,20 @@ 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 com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.LightType;
|
||||
|
||||
/**
|
||||
* This object is used to create NearFarBuffer objects.
|
||||
* @author James Seibel
|
||||
* @version 10-23-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodBufferBuilder
|
||||
{
|
||||
private static final MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
|
||||
/** The thread used to generate new LODs off the main thread. */
|
||||
public static final ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(LodBufferBuilder.class.getSimpleName() + " - main"));
|
||||
@@ -141,11 +138,11 @@ public class LodBufferBuilder
|
||||
private volatile RegionPos center;
|
||||
|
||||
/**
|
||||
* This is the ChunkPos the player was at the last time the buffers were built.
|
||||
* This is the ChunkPosWrapper the player was at the last time the buffers were built.
|
||||
* IE the center of the buffers last time they were built
|
||||
*/
|
||||
private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0, 0);
|
||||
private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0, 0);
|
||||
private volatile ChunkPosWrapper drawableCenterChunkPos = new ChunkPosWrapper(0, 0);
|
||||
private volatile ChunkPosWrapper buildableCenterChunkPos = new ChunkPosWrapper(0, 0);
|
||||
|
||||
|
||||
|
||||
@@ -167,7 +164,7 @@ public class LodBufferBuilder
|
||||
* swapped with the drawable buffers in the LodRenderer to be drawn.
|
||||
*/
|
||||
public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim,
|
||||
BlockPos playerBlockPos, boolean fullRegen)
|
||||
BlockPosWrapper playerBlockPos, boolean fullRegen)
|
||||
{
|
||||
|
||||
// only allow one generation process to happen at a time
|
||||
@@ -190,15 +187,15 @@ public class LodBufferBuilder
|
||||
// more easily edited by hot swapping. Because, As far as James is aware
|
||||
// you can't hot swap lambda expressions.
|
||||
private void generateLodBuffersThread(LodRenderer renderer, LodDimension lodDim,
|
||||
BlockPos playerBlockPos, boolean fullRegen)
|
||||
BlockPosWrapper playerBlockPos, boolean fullRegen)
|
||||
{
|
||||
bufferLock.lock();
|
||||
|
||||
try
|
||||
{
|
||||
// round the player's block position down to the nearest chunk BlockPos
|
||||
ChunkPos playerChunkPos = new ChunkPos(playerBlockPos);
|
||||
BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition();
|
||||
ChunkPosWrapper playerChunkPos = new ChunkPosWrapper(playerBlockPos);
|
||||
BlockPosWrapper playerBlockPosRounded = playerChunkPos.getWorldPosition();
|
||||
|
||||
|
||||
//long startTime = System.currentTimeMillis();
|
||||
@@ -232,8 +229,7 @@ public class LodBufferBuilder
|
||||
// create the nodeToRenderThreads //
|
||||
//================================//
|
||||
|
||||
ClientWorld world = mc.getClientWorld();
|
||||
skyLightPlayer = world.getBrightness(LightType.SKY, playerBlockPos);
|
||||
skyLightPlayer = MinecraftWrapper.INSTANCE.getWrappedClientLevel().getSkyLight(playerBlockPos);
|
||||
|
||||
for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++)
|
||||
{
|
||||
@@ -315,8 +311,8 @@ public class LodBufferBuilder
|
||||
posX = posToRender.getNthPosX(index);
|
||||
posZ = posToRender.getNthPosZ(index);
|
||||
|
||||
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x;
|
||||
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z;
|
||||
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.getX();
|
||||
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.getZ();
|
||||
|
||||
//We don't want to render this fake block if
|
||||
//The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered
|
||||
@@ -343,8 +339,8 @@ public class LodBufferBuilder
|
||||
xAdj = posX + Box.DIRECTION_NORMAL_MAP.get(direction).getX();
|
||||
zAdj = posZ + Box.DIRECTION_NORMAL_MAP.get(direction).getZ();
|
||||
long data;
|
||||
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x;
|
||||
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z;
|
||||
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.getX();
|
||||
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.getZ();
|
||||
adjPosInPlayerChunk = (chunkXdist == 0 && chunkZdist == 0);
|
||||
|
||||
//If the adj block is rendered in the same region and with same detail
|
||||
@@ -476,13 +472,13 @@ public class LodBufferBuilder
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, ChunkPos playerChunkPos, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
|
||||
private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, ChunkPosWrapper playerChunkPos, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){
|
||||
|
||||
|
||||
// skip any chunks that Minecraft is going to render
|
||||
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x;
|
||||
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z;
|
||||
|
||||
int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.getX();
|
||||
int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.getZ();
|
||||
|
||||
// check if the chunk is on the border
|
||||
boolean isItBorderPos;
|
||||
if (LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.get() == VanillaOverdraw.BORDER)
|
||||
@@ -519,13 +515,16 @@ public class LodBufferBuilder
|
||||
*/
|
||||
public void setupBuffers(LodDimension lodDimension)
|
||||
{
|
||||
GlProxy glProxy = GlProxy.getInstance();
|
||||
|
||||
bufferLock.lock();
|
||||
int numbRegionsWide = lodDimension.getWidth();
|
||||
long regionMemoryRequired;
|
||||
int numberOfBuffers;
|
||||
|
||||
GlProxy glProxy = GlProxy.getInstance();
|
||||
GlProxyContext oldContext = glProxy.getGlContext();
|
||||
glProxy.setGlContext(GlProxyContext.LOD_BUILDER);
|
||||
|
||||
|
||||
previousRegionWidth = numbRegionsWide;
|
||||
numberOfBuffersPerRegion = new int[numbRegionsWide][numbRegionsWide];
|
||||
buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide][];
|
||||
@@ -616,6 +615,7 @@ public class LodBufferBuilder
|
||||
}
|
||||
}
|
||||
|
||||
glProxy.setGlContext(oldContext);
|
||||
bufferLock.unlock();
|
||||
}
|
||||
|
||||
@@ -778,7 +778,11 @@ public class LodBufferBuilder
|
||||
for (int i = 0; i < buildableBuffers[x][z].length; i++)
|
||||
{
|
||||
ByteBuffer uploadBuffer = buildableBuffers[x][z][i].popNextBuffer().getSecond();
|
||||
vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z][i], uploadBuffer, true, uploadMethod);
|
||||
int storageBufferId = 0;
|
||||
if (buildableStorageBufferIds != null)
|
||||
storageBufferId = buildableStorageBufferIds[x][z][i];
|
||||
|
||||
vboUpload(buildableVbos[x][z][i], storageBufferId, uploadBuffer, true, uploadMethod);
|
||||
lodDim.setRegenRegionBufferByArrayIndex(x, z, false);
|
||||
}
|
||||
}
|
||||
@@ -793,7 +797,7 @@ public class LodBufferBuilder
|
||||
}
|
||||
finally
|
||||
{
|
||||
GL11.glFinish();
|
||||
GL15.glFinish();
|
||||
|
||||
// close the context so it can be re-used later.
|
||||
// I'm guessing we can't just leave it because the executor service
|
||||
@@ -810,14 +814,13 @@ public class LodBufferBuilder
|
||||
if (vbo.id != -1 && GlProxy.getInstance().getGlContext() == GlProxyContext.LOD_BUILDER)
|
||||
{
|
||||
// this is how many points will be rendered
|
||||
vbo.vertexCount = (uploadBuffer.capacity() / vbo.format.getVertexSize());
|
||||
|
||||
vbo.vertexCount = (uploadBuffer.capacity() / (Float.BYTES * 3) + (Byte.BYTES * 4)); // TODO make this change with the LodTemplate
|
||||
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id);
|
||||
try
|
||||
{
|
||||
// if possible use the faster buffer storage route
|
||||
if (uploadMethod == GpuUploadMethod.BUFFER_STORAGE)
|
||||
if (uploadMethod == GpuUploadMethod.BUFFER_STORAGE && storageBufferId != 0)
|
||||
{
|
||||
// get a pointer to the buffer in system memory
|
||||
ByteBuffer vboBuffer = GL30.glMapBufferRange(GL15.GL_ARRAY_BUFFER, 0, uploadBuffer.capacity(), GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
@@ -898,7 +901,6 @@ public class LodBufferBuilder
|
||||
// hybrid subData/bufferData //
|
||||
// less stutter, low GPU usage
|
||||
|
||||
//long size = GL31.glGetBufferParameteri64(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE); // hopefully just a int should be long enough
|
||||
long size = GL15.glGetBufferParameteri(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE);
|
||||
if (size < uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER)
|
||||
{
|
||||
@@ -953,9 +955,9 @@ public class LodBufferBuilder
|
||||
{
|
||||
public final VertexBuffer[][][] vbos;
|
||||
public final int[][][] storageBufferIds;
|
||||
public final ChunkPos drawableCenterChunkPos;
|
||||
public final ChunkPosWrapper drawableCenterChunkPos;
|
||||
|
||||
public VertexBuffersAndOffset(VertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, ChunkPos newDrawableCenterChunkPos)
|
||||
public VertexBuffersAndOffset(VertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, ChunkPosWrapper newDrawableCenterChunkPos)
|
||||
{
|
||||
vbos = newVbos;
|
||||
storageBufferIds = newStorageBufferIds;
|
||||
|
||||
+2
-2
@@ -23,10 +23,10 @@ import java.util.Map;
|
||||
|
||||
import com.seibel.lod.enums.DebugMode;
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* This is the abstract class used to create different
|
||||
@@ -38,7 +38,7 @@ public abstract class AbstractLodTemplate
|
||||
{
|
||||
|
||||
/** Uploads the given LOD to the buffer. */
|
||||
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPosWrapper bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled);
|
||||
|
||||
/** add the given position and color to the buffer */
|
||||
|
||||
@@ -28,10 +28,10 @@ import com.seibel.lod.enums.DebugMode;
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.util.DataPointUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Vector3i;
|
||||
|
||||
/**
|
||||
@@ -74,35 +74,58 @@ public class Box
|
||||
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 } });
|
||||
{ 0, 1, 0 }, // 0
|
||||
{ 0, 1, 1 }, // 1
|
||||
{ 1, 1, 1 }, // 2
|
||||
|
||||
{ 0, 1, 0 }, // 0
|
||||
{ 1, 1, 1 }, // 2
|
||||
{ 1, 1, 0 } // 3
|
||||
});
|
||||
put(Direction.DOWN, new int[][] {
|
||||
{ 1, 0, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ 0, 0, 1 },
|
||||
{ 0, 0, 0 } });
|
||||
{ 1, 0, 0 }, // 0
|
||||
{ 1, 0, 1 }, // 1
|
||||
{ 0, 0, 1 }, // 2
|
||||
|
||||
{ 1, 0, 0 }, // 0
|
||||
{ 0, 0, 1 }, // 2
|
||||
{ 0, 0, 0 } // 3
|
||||
});
|
||||
put(Direction.EAST, new int[][] {
|
||||
{ 1, 1, 0 },
|
||||
{ 1, 1, 1 },
|
||||
{ 1, 0, 1 },
|
||||
{ 1, 0, 0 } });
|
||||
{ 1, 1, 0 }, // 0
|
||||
{ 1, 1, 1 }, // 1
|
||||
{ 1, 0, 1 }, // 2
|
||||
|
||||
{ 1, 1, 0 }, // 0
|
||||
{ 1, 0, 1 }, // 2
|
||||
{ 1, 0, 0 } }); // 3
|
||||
put(Direction.WEST, new int[][] {
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0, 1, 0 } });
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 0, 0, 1 }, // 1
|
||||
{ 0, 1, 1 }, // 2
|
||||
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 0, 1, 1 }, // 2
|
||||
{ 0, 1, 0 } // 3
|
||||
});
|
||||
put(Direction.SOUTH, new int[][] {
|
||||
{ 1, 0, 1 },
|
||||
{ 1, 1, 1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0, 0, 1 } });
|
||||
{ 1, 0, 1 }, // 0
|
||||
{ 1, 1, 1 }, // 1
|
||||
{ 0, 1, 1 }, // 2
|
||||
|
||||
{ 1, 0, 1 }, // 0
|
||||
{ 0, 1, 1 }, // 2
|
||||
{ 0, 0, 1 } // 3
|
||||
});
|
||||
put(Direction.NORTH, new int[][] {
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 1, 0 },
|
||||
{ 1, 1, 0 },
|
||||
{ 1, 0, 0 } });
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 0, 1, 0 }, // 1
|
||||
{ 1, 1, 0 }, // 2
|
||||
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 1, 1, 0 }, // 2
|
||||
{ 1, 0, 0 } // 3
|
||||
});
|
||||
}};
|
||||
|
||||
|
||||
@@ -226,7 +249,7 @@ public class Box
|
||||
for (Direction direction : DIRECTIONS)
|
||||
{
|
||||
if (!adjShadeDisabled[DIRECTION_INDEX.get(direction)])
|
||||
colorMap[DIRECTION_INDEX.get(direction)] = ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientWorld().getShade(direction, true));
|
||||
colorMap[DIRECTION_INDEX.get(direction)] = ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientLevel().getShade(direction, true));
|
||||
else
|
||||
colorMap[DIRECTION_INDEX.get(direction)] = color;
|
||||
}
|
||||
@@ -241,7 +264,7 @@ public class Box
|
||||
if (LodConfig.CLIENT.advancedModOptions.debugging.debugMode.get() != DebugMode.SHOW_DETAIL)
|
||||
return colorMap[DIRECTION_INDEX.get(direction)];
|
||||
else
|
||||
return ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientWorld().getShade(direction, true));
|
||||
return ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientLevel().getShade(direction, true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,7 +302,7 @@ public class Box
|
||||
}
|
||||
|
||||
/** determine which faces should be culled */
|
||||
public void setUpCulling(int cullingDistance, BlockPos playerPos)
|
||||
public void setUpCulling(int cullingDistance, BlockPosWrapper playerPos)
|
||||
{
|
||||
for (Direction direction : DIRECTIONS)
|
||||
{
|
||||
|
||||
+7
-5
@@ -25,15 +25,16 @@ import com.seibel.lod.enums.DebugMode;
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.util.DataPointUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* Builds LODs as rectangular prisms.
|
||||
* @author James Seibel
|
||||
* @version 10-10-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class CubicLodTemplate extends AbstractLodTemplate
|
||||
{
|
||||
@@ -44,7 +45,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
public void addLodToBuffer(BufferBuilder buffer, BlockPosWrapper bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled)
|
||||
{
|
||||
if (box == null)
|
||||
@@ -79,7 +80,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
|
||||
private void generateBoundingBox(Box box,
|
||||
int height, int depth, int width,
|
||||
double xOffset, double yOffset, double zOffset,
|
||||
BlockPos bufferCenterBlockPos,
|
||||
BlockPosWrapper bufferCenterBlockPos,
|
||||
Map<Direction, long[]> adjData,
|
||||
int color,
|
||||
int skyLight,
|
||||
@@ -118,10 +119,11 @@ public class CubicLodTemplate extends AbstractLodTemplate
|
||||
{
|
||||
if(box.isCulled(direction))
|
||||
continue;
|
||||
|
||||
int verticalFaceIndex = 0;
|
||||
while (box.shouldRenderFace(direction, verticalFaceIndex))
|
||||
{
|
||||
for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++)
|
||||
for (int vertexIndex = 0; vertexIndex < 6; vertexIndex++)
|
||||
{
|
||||
color = box.getColor(direction);
|
||||
skyLight = box.getSkyLight(direction, verticalFaceIndex);
|
||||
|
||||
+2
-2
@@ -24,9 +24,9 @@ import java.util.Map;
|
||||
import com.seibel.lod.enums.DebugMode;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* TODO DynamicLodTemplate
|
||||
@@ -39,7 +39,7 @@ import net.minecraft.util.math.BlockPos;
|
||||
public class DynamicLodTemplate extends AbstractLodTemplate
|
||||
{
|
||||
@Override
|
||||
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
public void addLodToBuffer(BufferBuilder buffer, BlockPosWrapper bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled)
|
||||
{
|
||||
ClientProxy.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
|
||||
|
||||
+2
-2
@@ -24,9 +24,9 @@ import java.util.Map;
|
||||
import com.seibel.lod.enums.DebugMode;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* TODO #21 TriangularLodTemplate
|
||||
@@ -37,7 +37,7 @@ import net.minecraft.util.math.BlockPos;
|
||||
public class TriangularLodTemplate extends AbstractLodTemplate
|
||||
{
|
||||
@Override
|
||||
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
public void addLodToBuffer(BufferBuilder buffer, BlockPosWrapper bufferCenterBlockPos, long data, Map<Direction, long[]> adjData,
|
||||
byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled)
|
||||
{
|
||||
ClientProxy.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!");
|
||||
|
||||
@@ -41,9 +41,8 @@ import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockShapeWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import com.seibel.lod.wrappers.World.BiomeColorWrapper;
|
||||
import com.seibel.lod.wrappers.World.BiomeWrapper;
|
||||
import com.seibel.lod.wrappers.World.WorldWrapper;
|
||||
import com.seibel.lod.wrappers.World.LevelWrapper;
|
||||
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.IWorld;
|
||||
@@ -109,7 +108,7 @@ public class LodBuilder
|
||||
{
|
||||
// we need a loaded client world in order to
|
||||
// get the textures for blocks
|
||||
if (mc.getClientWorld() == null)
|
||||
if (mc.getClientLevel() == null)
|
||||
return;
|
||||
|
||||
// don't try to generate LODs if the user isn't in the world anymore
|
||||
@@ -171,7 +170,7 @@ public class LodBuilder
|
||||
return;
|
||||
|
||||
// this happens if a LOD is generated after the user leaves the world.
|
||||
if (MinecraftWrapper.INSTANCE.getWrappedClientWorld() == null)
|
||||
if (MinecraftWrapper.INSTANCE.getWrappedClientLevel() == null)
|
||||
return;
|
||||
|
||||
// determine how many LODs to generate horizontally
|
||||
@@ -231,8 +230,8 @@ public class LodBuilder
|
||||
int xAbs;
|
||||
int yAbs;
|
||||
int zAbs;
|
||||
boolean hasCeiling = mc.getClientWorld().dimensionType().hasCeiling();
|
||||
boolean hasSkyLight = mc.getClientWorld().dimensionType().hasSkyLight();
|
||||
boolean hasCeiling = mc.getClientLevel().dimensionType().hasCeiling();
|
||||
boolean hasSkyLight = mc.getClientLevel().dimensionType().hasSkyLight();
|
||||
boolean isDefault;
|
||||
BlockPosWrapper blockPos = new BlockPosWrapper();
|
||||
int index;
|
||||
@@ -387,7 +386,7 @@ public class LodBuilder
|
||||
// 1 means the lighting is a guess
|
||||
int isDefault = 0;
|
||||
|
||||
WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld();
|
||||
LevelWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerLevel();
|
||||
|
||||
int blockBrightness = chunk.getEmittedBrightness(blockPos);
|
||||
// get the air block above or below this block
|
||||
@@ -415,7 +414,7 @@ public class LodBuilder
|
||||
{
|
||||
// we are on predicted terrain, and we don't know what the light here is,
|
||||
// lets just take a guess
|
||||
if (blockPos.getY() >= mc.getClientWorld().getSeaLevel() - 5)
|
||||
if (blockPos.getY() >= mc.getClientLevel().getSeaLevel() - 5)
|
||||
{
|
||||
skyLight = 12;
|
||||
isDefault = 1;
|
||||
@@ -426,7 +425,7 @@ public class LodBuilder
|
||||
}
|
||||
else
|
||||
{
|
||||
world = MinecraftWrapper.INSTANCE.getWrappedClientWorld();
|
||||
world = MinecraftWrapper.INSTANCE.getWrappedClientLevel();
|
||||
if (world.isEmpty())
|
||||
return 0;
|
||||
// client world sky light (almost never accurate)
|
||||
@@ -448,7 +447,7 @@ public class LodBuilder
|
||||
{
|
||||
// we don't know what the light here is,
|
||||
// lets just take a guess
|
||||
if (blockPos.getY() >= mc.getClientWorld().getSeaLevel() - 5)
|
||||
if (blockPos.getY() >= mc.getClientLevel().getSeaLevel() - 5)
|
||||
{
|
||||
skyLight = 12;
|
||||
isDefault = 1;
|
||||
@@ -485,10 +484,7 @@ public class LodBuilder
|
||||
BlockShapeWrapper blockShapeWrapper = chunk.getBlockShapeWrapper(blockPos);
|
||||
|
||||
if (chunk.isWaterLogged(blockPos))
|
||||
{
|
||||
BiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
|
||||
return biome.getWaterTint();
|
||||
}
|
||||
blockColorWrapper = BlockColorWrapper.getWaterColor();
|
||||
else
|
||||
blockColorWrapper = chunk.getBlockColorWrapper(blockPos);
|
||||
|
||||
@@ -500,20 +496,16 @@ public class LodBuilder
|
||||
|
||||
if (blockColorWrapper.hasTint())
|
||||
{
|
||||
WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld();
|
||||
|
||||
if (world == null || world.isEmpty())
|
||||
world = MinecraftWrapper.INSTANCE.getWrappedClientWorld();
|
||||
|
||||
BiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
|
||||
int tintValue;
|
||||
if (blockColorWrapper.hasGrassTint())
|
||||
// grass and green plants
|
||||
tintValue = BiomeColorWrapper.getGrassColor(world, blockPos);
|
||||
tintValue = biome.getGrassTint(0,0);
|
||||
else if (blockColorWrapper.hasFolliageTint())
|
||||
tintValue = BiomeColorWrapper.getFoliageColor(world, blockPos);
|
||||
tintValue = biome.getFolliageTint();
|
||||
else
|
||||
//we can reintroduce this with the wrappers
|
||||
tintValue = BiomeColorWrapper.getWaterColor(world, blockPos);
|
||||
tintValue = biome.getWaterTint();
|
||||
|
||||
colorInt = ColorUtil.multiplyRGBcolors(tintValue | 0xFF000000, colorOfBlock);
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.palette.UpgradeData;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
@@ -90,7 +90,7 @@ public class LodGenWorker implements IWorker
|
||||
|
||||
|
||||
|
||||
public LodGenWorker(ChunkPos newPos, DistanceGenerationMode newGenerationMode,
|
||||
public LodGenWorker(ChunkPosWrapper newPos, DistanceGenerationMode newGenerationMode,
|
||||
LodBuilder newLodBuilder,
|
||||
LodDimension newLodDimension, ServerWorld newServerWorld)
|
||||
{
|
||||
@@ -161,9 +161,9 @@ public class LodGenWorker implements IWorker
|
||||
public final DistanceGenerationMode generationMode;
|
||||
public final LodBuilder lodBuilder;
|
||||
|
||||
private final ChunkPos pos;
|
||||
private final ChunkPosWrapper pos;
|
||||
|
||||
public LodChunkGenThread(ChunkPos newPos, DistanceGenerationMode newGenerationMode,
|
||||
public LodChunkGenThread(ChunkPosWrapper newPos, DistanceGenerationMode newGenerationMode,
|
||||
LodBuilder newLodBuilder,
|
||||
LodDimension newLodDimension, ServerWorld newServerWorld)
|
||||
{
|
||||
@@ -177,13 +177,13 @@ public class LodGenWorker implements IWorker
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
//try
|
||||
//{
|
||||
// only generate LodChunks if they can
|
||||
// be added to the current LodDimension
|
||||
|
||||
/* TODO I must disable this 'if', if I will find a way to replace it */
|
||||
if (lodDim.regionIsInRange(pos.x / LodUtil.REGION_WIDTH_IN_CHUNKS, pos.z / LodUtil.REGION_WIDTH_IN_CHUNKS))
|
||||
if (lodDim.regionIsInRange(pos.getX() / LodUtil.REGION_WIDTH_IN_CHUNKS, pos.getZ() / LodUtil.REGION_WIDTH_IN_CHUNKS))
|
||||
{
|
||||
//
|
||||
//{
|
||||
@@ -270,20 +270,20 @@ public class LodGenWorker implements IWorker
|
||||
// System.out.println(endTime - startTime);
|
||||
|
||||
}// if in range
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ClientProxy.LOGGER.error(LodChunkGenThread.class.getSimpleName() + ": ran into an error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
//}
|
||||
//catch (Exception e)
|
||||
//{
|
||||
// ClientProxy.LOGGER.error(LodChunkGenThread.class.getSimpleName() + ": ran into an error: " + e.getMessage());
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
//finally
|
||||
//{
|
||||
// decrement how many threads are running
|
||||
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.addAndGet(-1);
|
||||
|
||||
// this position is no longer being generated
|
||||
LodWorldGenerator.INSTANCE.positionsWaitingToBeGenerated.remove(pos);
|
||||
}
|
||||
//}
|
||||
|
||||
}// run
|
||||
|
||||
@@ -295,7 +295,7 @@ public class LodGenWorker implements IWorker
|
||||
private void generateUsingBiomesOnly()
|
||||
{
|
||||
List<IChunk> chunkList = new LinkedList<>();
|
||||
ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY);
|
||||
ChunkPrimer chunk = new ChunkPrimer(pos.getChunkPos(), UpgradeData.EMPTY);
|
||||
chunkList.add(chunk);
|
||||
|
||||
ServerChunkProvider chunkSource = serverWorld.getChunkSource();
|
||||
@@ -407,7 +407,7 @@ public class LodGenWorker implements IWorker
|
||||
private void generateUsingSurface()
|
||||
{
|
||||
List<IChunk> chunkList = new LinkedList<>();
|
||||
ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY);
|
||||
ChunkPrimer chunk = new ChunkPrimer(pos.getChunkPos(), UpgradeData.EMPTY);
|
||||
chunkList.add(chunk);
|
||||
LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk);
|
||||
|
||||
@@ -447,7 +447,7 @@ public class LodGenWorker implements IWorker
|
||||
private void generateUsingFeatures()
|
||||
{
|
||||
List<IChunk> chunkList = new LinkedList<>();
|
||||
ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY);
|
||||
ChunkPrimer chunk = new ChunkPrimer(pos.getChunkPos(), UpgradeData.EMPTY);
|
||||
chunkList.add(chunk);
|
||||
LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk);
|
||||
|
||||
@@ -565,7 +565,7 @@ public class LodGenWorker implements IWorker
|
||||
*/
|
||||
private void generateWithServer()
|
||||
{
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES)), new LodBuilderConfig(DistanceGenerationMode.SERVER));
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(serverWorld.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FEATURES)), new LodBuilderConfig(DistanceGenerationMode.SERVER));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ 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.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.WorldWorkerManager;
|
||||
|
||||
@@ -72,7 +72,7 @@ public class LodWorldGenerator
|
||||
*/
|
||||
public final AtomicInteger numberOfChunksWaitingToGenerate = new AtomicInteger(0);
|
||||
|
||||
public final Set<ChunkPos> positionsWaitingToBeGenerated = new HashSet<>();
|
||||
public final Set<ChunkPosWrapper> positionsWaitingToBeGenerated = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Singleton copy of this object
|
||||
@@ -142,7 +142,7 @@ public class LodWorldGenerator
|
||||
posZ = posToGenerate.getNthPosZ(nearIndex, true);
|
||||
nearIndex++;
|
||||
|
||||
ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ));
|
||||
ChunkPosWrapper chunkPos = new ChunkPosWrapper(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ));
|
||||
|
||||
// prevent generating the same chunk multiple times
|
||||
if (positionsWaitingToBeGenerated.contains(chunkPos))
|
||||
@@ -167,7 +167,7 @@ public class LodWorldGenerator
|
||||
posZ = posToGenerate.getNthPosZ(farIndex, false);
|
||||
farIndex++;
|
||||
|
||||
ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ));
|
||||
ChunkPosWrapper chunkPos = new ChunkPosWrapper(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ));
|
||||
|
||||
// don't add more to the generation queue then allowed
|
||||
if (numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests)
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.File;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import com.seibel.lod.wrappers.World.LevelWrapper;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.chunk.IChunk;
|
||||
import net.minecraft.world.chunk.storage.ChunkSerializer;
|
||||
@@ -39,10 +39,10 @@ public class ChunkLoader
|
||||
{
|
||||
public static IChunk getChunkFromFile(ChunkPos pos){
|
||||
|
||||
ClientWorld clientWorld = MinecraftWrapper.INSTANCE.getClientWorld();
|
||||
if (clientWorld == null)
|
||||
LevelWrapper clientLevel = MinecraftWrapper.INSTANCE.getWrappedClientLevel();
|
||||
if (clientLevel == null)
|
||||
return null;
|
||||
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(clientWorld.dimensionType());
|
||||
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(clientLevel.getWorld().dimensionType());
|
||||
try
|
||||
{
|
||||
File file = new File(serverWorld.getChunkSource().getDataStorage().dataFolder.getParent() + File.separatorChar + "region", "r." + (pos.x >> 5) + "." + (pos.z >> 5) + ".mca");
|
||||
|
||||
@@ -19,11 +19,9 @@
|
||||
|
||||
package com.seibel.lod.handlers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -236,9 +234,7 @@ public class LodDimensionFileHandler
|
||||
// Save to File //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* Save all dirty regions in this LodDimension to file.
|
||||
*/
|
||||
/** Save all dirty regions in this LodDimension to file */
|
||||
public void saveDirtyRegionsToFileAsync()
|
||||
{
|
||||
fileWritingThreadPool.execute(saveDirtyRegionsThread);
|
||||
@@ -289,6 +285,7 @@ public class LodDimensionFileHandler
|
||||
}
|
||||
File oldFile = new File(fileName);
|
||||
//ClientProxy.LOGGER.info("saving region [" + region.regionPosX + ", " + region.regionPosZ + "] to file.");
|
||||
byte[] temp = region.getLevel(detailLevel).toDataString();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -308,9 +305,12 @@ public class LodDimensionFileHandler
|
||||
// (to make sure we don't overwrite a newer
|
||||
// version file if it exists)
|
||||
int fileVersion = LOD_SAVE_FILE_VERSION;
|
||||
int isFull = 0;
|
||||
try (XZCompressorInputStream inputStream = new XZCompressorInputStream(new FileInputStream(oldFile)))
|
||||
{
|
||||
fileVersion = inputStream.read();
|
||||
inputStream.skip(1);
|
||||
isFull = inputStream.read() & 0b10000000;
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex)
|
||||
@@ -326,11 +326,17 @@ public class LodDimensionFileHandler
|
||||
// delete anything the user may want.
|
||||
return;
|
||||
}
|
||||
|
||||
if ((temp[1] & 0b10000000) != 0b10000000 && isFull == 0b10000000)
|
||||
{
|
||||
// existing file is complete while new one is only partially generate
|
||||
// this can happen is for some reason loading failed
|
||||
// this doesn't fix the bug, but at least protects old data
|
||||
ClientProxy.LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + fileName + "]");
|
||||
return;
|
||||
}
|
||||
// if we got this far then we are good
|
||||
// to overwrite the old file
|
||||
}
|
||||
|
||||
// the old file is good, now create a new temporary save file
|
||||
File newFile = new File(fileName + TMP_FILE_EXTENSION);
|
||||
try (XZCompressorOutputStream outputStream = new XZCompressorOutputStream(new FileOutputStream(newFile), 3))
|
||||
@@ -339,7 +345,7 @@ public class LodDimensionFileHandler
|
||||
outputStream.write(LOD_SAVE_FILE_VERSION);
|
||||
|
||||
// add each LodChunk to the file
|
||||
outputStream.write(region.getLevel(detailLevel).toDataString());
|
||||
outputStream.write(temp);
|
||||
outputStream.close();
|
||||
|
||||
// overwrite the old file with the new one
|
||||
@@ -366,6 +372,22 @@ public class LodDimensionFileHandler
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
public byte[] getHashFromFile(byte detailLevel, RegionPos regionPos, DistanceGenerationMode generationMode, VerticalQuality verticalQuality)
|
||||
{
|
||||
int regionX = regionPos.x;
|
||||
int regionZ = regionPos.z;
|
||||
String fileName = getFileNameAndPathForRegion(regionX, regionZ, generationMode, detailLevel, verticalQuality);
|
||||
try (InputStream is = Files.newInputStream(Paths.get(fileName))) {
|
||||
return org.apache.commons.codec.digest.DigestUtils.md5(is);
|
||||
}
|
||||
catch (IOException ioEx)
|
||||
{
|
||||
ClientProxy.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: ");
|
||||
ioEx.printStackTrace();
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the file that should contain the
|
||||
|
||||
@@ -37,7 +37,6 @@ import java.lang.reflect.Method;
|
||||
public class ReflectionHandler
|
||||
{
|
||||
public static final ReflectionHandler INSTANCE = new ReflectionHandler();
|
||||
private final MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
|
||||
public Field ofFogField = null;
|
||||
public Method vertexBufferUploadMethod = null;
|
||||
@@ -56,7 +55,7 @@ public class ReflectionHandler
|
||||
private void setupFogField()
|
||||
{
|
||||
// get every variable from the entity renderer
|
||||
Field[] optionFields = mc.getOptions().getClass().getDeclaredFields();
|
||||
Field[] optionFields = MinecraftWrapper.INSTANCE.getOptions().getClass().getDeclaredFields();
|
||||
|
||||
// try and find the ofFogType variable in gameSettings
|
||||
for (Field field : optionFields)
|
||||
@@ -93,7 +92,7 @@ public class ReflectionHandler
|
||||
|
||||
try
|
||||
{
|
||||
returnNum = (int) ofFogField.get(mc.getOptions());
|
||||
returnNum = (int) ofFogField.get(MinecraftWrapper.INSTANCE.getOptions());
|
||||
}
|
||||
catch (IllegalArgumentException | IllegalAccessException e)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
|
||||
import com.seibel.lod.wrappers.World.DimensionTypeWrapper;
|
||||
import net.minecraft.world.DimensionType;
|
||||
|
||||
/**
|
||||
@@ -39,7 +40,7 @@ public class LodWorld
|
||||
private String worldName;
|
||||
|
||||
/** dimensions in this world */
|
||||
private Map<DimensionType, LodDimension> lodDimensions;
|
||||
private Map<DimensionTypeWrapper, LodDimension> lodDimensions;
|
||||
|
||||
/** If true then the LOD world is setup and ready to use */
|
||||
private boolean isWorldLoaded = false;
|
||||
@@ -107,7 +108,7 @@ public class LodWorld
|
||||
if (lodDimensions == null)
|
||||
return;
|
||||
|
||||
lodDimensions.put(newDimension.dimension, newDimension);
|
||||
lodDimensions.put(DimensionTypeWrapper.getDimensionTypeWrapper(newDimension.dimension), newDimension);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +119,7 @@ public class LodWorld
|
||||
if (lodDimensions == null)
|
||||
return null;
|
||||
|
||||
return lodDimensions.get(dimension);
|
||||
return lodDimensions.get(DimensionTypeWrapper.getDimensionTypeWrapper(dimension));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +133,7 @@ public class LodWorld
|
||||
|
||||
saveAllDimensions();
|
||||
|
||||
for (DimensionType key : lodDimensions.keySet())
|
||||
for (DimensionTypeWrapper key : lodDimensions.keySet())
|
||||
lodDimensions.get(key).setRegionWidth(newRegionWidth);
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ public class LodWorld
|
||||
// but that requires a LodDimension.hasDirtyRegions() method or something similar
|
||||
ClientProxy.LOGGER.info("Saving LODs");
|
||||
|
||||
for (DimensionType key : lodDimensions.keySet())
|
||||
for (DimensionTypeWrapper key : lodDimensions.keySet())
|
||||
lodDimensions.get(key).saveDirtyRegionsToFileAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
package com.seibel.lod.objects;
|
||||
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
|
||||
/**
|
||||
* This object is similar to ChunkPos or BlockPos.
|
||||
@@ -55,28 +54,28 @@ public class RegionPos
|
||||
}
|
||||
|
||||
/** Converts from a BlockPos to a RegionPos */
|
||||
public RegionPos(BlockPos pos)
|
||||
public RegionPos(BlockPosWrapper pos)
|
||||
{
|
||||
this(new ChunkPos(pos));
|
||||
this(new ChunkPosWrapper(pos));
|
||||
}
|
||||
|
||||
/** Converts from a ChunkPos to a RegionPos */
|
||||
public RegionPos(ChunkPos pos)
|
||||
public RegionPos(ChunkPosWrapper pos)
|
||||
{
|
||||
x = Math.floorDiv(pos.x, LodUtil.REGION_WIDTH_IN_CHUNKS);
|
||||
z = Math.floorDiv(pos.z, LodUtil.REGION_WIDTH_IN_CHUNKS);
|
||||
x = Math.floorDiv(pos.getX(), LodUtil.REGION_WIDTH_IN_CHUNKS);
|
||||
z = Math.floorDiv(pos.getZ(), LodUtil.REGION_WIDTH_IN_CHUNKS);
|
||||
}
|
||||
|
||||
/** Returns the ChunkPos at the center of this region */
|
||||
public ChunkPos chunkPos()
|
||||
public ChunkPosWrapper chunkPos()
|
||||
{
|
||||
return new ChunkPos(
|
||||
return new ChunkPosWrapper(
|
||||
(x * LodUtil.REGION_WIDTH_IN_CHUNKS) + LodUtil.REGION_WIDTH_IN_CHUNKS / 2,
|
||||
(z * LodUtil.REGION_WIDTH_IN_CHUNKS) + LodUtil.REGION_WIDTH_IN_CHUNKS / 2);
|
||||
}
|
||||
|
||||
/** Returns the BlockPos at the center of this region */
|
||||
public BlockPos blockPos()
|
||||
public BlockPosWrapper blockPos()
|
||||
{
|
||||
return chunkPos().getWorldPosition()
|
||||
.offset(LodUtil.CHUNK_WIDTH / 2, 0, LodUtil.CHUNK_WIDTH / 2);
|
||||
|
||||
@@ -129,7 +129,7 @@ public class VerticalLevelContainer implements LevelContainer
|
||||
long newData;
|
||||
detailLevel = inputData[index];
|
||||
index++;
|
||||
maxVerticalData = inputData[index];
|
||||
maxVerticalData = inputData[index] & 0b01111111;
|
||||
index++;
|
||||
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
|
||||
int x = size * size * maxVerticalData;
|
||||
@@ -181,24 +181,31 @@ public class VerticalLevelContainer implements LevelContainer
|
||||
public byte[] toDataString()
|
||||
{
|
||||
int index = 0;
|
||||
int x = size * size * maxVerticalData;
|
||||
int x = size * size;
|
||||
int tempIndex;
|
||||
long current;
|
||||
|
||||
boolean allGenerated = true;
|
||||
byte[] tempData = ThreadMapUtil.getSaveContainer(detailLevel);
|
||||
|
||||
tempData[index] = detailLevel;
|
||||
index++;
|
||||
tempData[index] = (byte) maxVerticalData;
|
||||
index++;
|
||||
|
||||
int j;
|
||||
for (int i = 0; i < x; i++)
|
||||
{
|
||||
current = dataContainer[i];
|
||||
for (tempIndex = 0; tempIndex < 8; tempIndex++)
|
||||
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
|
||||
index += 8;
|
||||
for (j = 0; j < maxVerticalData; j++)
|
||||
{
|
||||
current = dataContainer[i * maxVerticalData + j];
|
||||
for (tempIndex = 0; tempIndex < 8; tempIndex++)
|
||||
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
|
||||
index += 8;
|
||||
}
|
||||
if(!DataPointUtil.doesItExist(dataContainer[i]))
|
||||
allGenerated = false;
|
||||
}
|
||||
if (allGenerated)
|
||||
tempData[1] |= 0b10000000;
|
||||
return tempData;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
|
||||
package com.seibel.lod.proxy;
|
||||
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder;
|
||||
@@ -40,8 +40,10 @@ import com.seibel.lod.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.util.ThreadMapUtil;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
|
||||
import net.minecraft.profiler.IProfiler;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import net.minecraftforge.client.event.InputEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
@@ -54,7 +56,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
* This handles all events sent to the client,
|
||||
* and is the starting point for most of the mod.
|
||||
* @author James_Seibel
|
||||
* @version 10-23-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class ClientProxy
|
||||
{
|
||||
@@ -99,7 +101,7 @@ public class ClientProxy
|
||||
//==============//
|
||||
|
||||
/** Do any setup that is required to draw LODs and then tell the LodRenderer to draw. */
|
||||
public void renderLods(MatrixStack mcMatrixStack, float partialTicks)
|
||||
public void renderLods(MatrixStack mcModelViewMatrix, float partialTicks)
|
||||
{
|
||||
// comment out when creating a release
|
||||
// applyConfigOverrides();
|
||||
@@ -129,6 +131,15 @@ public class ClientProxy
|
||||
lodDim.expandOrLoadRegionsAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ());
|
||||
|
||||
|
||||
// get the default projection matrix, so we can
|
||||
// reset it after drawing the LODs
|
||||
float[] mcProjMatrixRaw = new float[16];
|
||||
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
|
||||
Matrix4f mcProjectionMatrix = new Matrix4f(mcProjMatrixRaw);
|
||||
// OpenGl outputs their matrices in col,row form instead of row,col
|
||||
// (or maybe vice versa I have no idea :P)
|
||||
mcProjectionMatrix.transpose();
|
||||
|
||||
// Note to self:
|
||||
// if "unspecified" shows up in the pie chart, it is
|
||||
// possibly because the amount of time between sections
|
||||
@@ -137,7 +148,8 @@ public class ClientProxy
|
||||
profiler.pop(); // get out of "terrain"
|
||||
profiler.push("LOD");
|
||||
|
||||
renderer.drawLODs(lodDim, mcMatrixStack, partialTicks, mc.getProfiler());
|
||||
|
||||
renderer.drawLODs(lodDim, mcModelViewMatrix, mcProjectionMatrix, partialTicks, mc.getProfiler());
|
||||
|
||||
profiler.pop(); // end LOD
|
||||
profiler.push("terrain"); // go back into "terrain"
|
||||
@@ -161,18 +173,19 @@ public class ClientProxy
|
||||
// remind the developer(s) that the config override is active
|
||||
if (!configOverrideReminderPrinted)
|
||||
{
|
||||
// TODO add a send message method to the MC wrapper
|
||||
// mc.getPlayer().sendMessage(new StringTextComponent("LOD experimental build 1.5.1"), mc.getPlayer().getUUID());
|
||||
// mc.getPlayer().sendMessage(new StringTextComponent("Here be dragons!"), mc.getPlayer().getUUID());
|
||||
|
||||
mc.getPlayer().sendMessage(new StringTextComponent("Debug settings enabled!"), mc.getPlayer().getUUID());
|
||||
configOverrideReminderPrinted = true;
|
||||
}
|
||||
|
||||
|
||||
// LodConfig.CLIENT.graphics.drawResolution.set(HorizontalResolution.BLOCK);
|
||||
// LodConfig.CLIENT.worldGenerator.generationResolution.set(HorizontalResolution.BLOCK);
|
||||
// requires a world restart?
|
||||
// LodConfig.CLIENT.worldGenerator.lodQualityMode.set(VerticalQuality.VOXEL);
|
||||
|
||||
|
||||
// LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.set(FogDistance.FAR);
|
||||
// LodConfig.CLIENT.graphics.fogQualityOption.fogDrawOverride.set(FogDrawOverride.FANCY);
|
||||
// LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.set(true);
|
||||
@@ -181,7 +194,7 @@ public class ClientProxy
|
||||
// LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.set(VanillaOverdraw.DYNAMIC);
|
||||
|
||||
// LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.set(GpuUploadMethod.BUFFER_STORAGE);
|
||||
|
||||
|
||||
// LodConfig.CLIENT.worldGenerator.distanceGenerationMode.set(DistanceGenerationMode.SURFACE);
|
||||
// LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.set(128);
|
||||
// LodConfig.CLIENT.worldGenerator.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR);
|
||||
@@ -250,23 +263,25 @@ public class ClientProxy
|
||||
{
|
||||
// the player just left the server
|
||||
|
||||
// TODO should "resetMod()" be called here? -James
|
||||
|
||||
// if this isn't done unfinished tasks may be left in the queue
|
||||
// preventing new LodChunks form being generated
|
||||
//LodNodeGenWorker.restartExecutorService();
|
||||
//LodNodeGenWorker.restartExecutorService(); // TODO why was this commented out? -James
|
||||
//ThreadMapUtil.clearMaps();
|
||||
|
||||
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
|
||||
lodWorld.deselectWorld();
|
||||
|
||||
|
||||
// hopefully this should reduce issues related to the buffer builder
|
||||
// prevent issues related to the buffer builder
|
||||
// breaking when changing worlds.
|
||||
renderer.destroyBuffers();
|
||||
recalculateWidths = true;
|
||||
renderer = new LodRenderer(lodBufferBuilder);
|
||||
|
||||
|
||||
// make sure the nilled objects are freed.
|
||||
// make sure the nulled objects are freed.
|
||||
// (this prevents an out of memory error when
|
||||
// changing worlds)
|
||||
System.gc();
|
||||
@@ -314,7 +329,7 @@ public class ClientProxy
|
||||
private void playerMoveEvent(LodDimension lodDim)
|
||||
{
|
||||
// make sure the dimension is centered
|
||||
RegionPos playerRegionPos = new RegionPos(mc.getPlayer().blockPosition());
|
||||
RegionPos playerRegionPos = new RegionPos(mc.getPlayerBlockPos());
|
||||
RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterRegionPosX(), playerRegionPos.z - lodDim.getCenterRegionPosZ());
|
||||
if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0)
|
||||
{
|
||||
@@ -330,7 +345,7 @@ public class ClientProxy
|
||||
{
|
||||
// calculate how wide the dimension(s) should be in regions
|
||||
int chunksWide;
|
||||
if (mc.getClientWorld().dimensionType().hasCeiling())
|
||||
if (mc.getClientLevel().dimensionType().hasCeiling())
|
||||
chunksWide = Math.min(LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * 2 + 1;
|
||||
else
|
||||
chunksWide = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * 2 + 1;
|
||||
@@ -347,7 +362,7 @@ public class ClientProxy
|
||||
// update the dimensions to fit the new width
|
||||
lodWorld.resizeDimensionRegionWidth(newWidth);
|
||||
lodBuilder.defaultDimensionWidthInRegions = newWidth;
|
||||
renderer.setupBuffers(lodWorld.getLodDimension(mc.getClientWorld().dimensionType()));
|
||||
renderer.setupBuffers(lodWorld.getLodDimension(mc.getClientLevel().dimensionType()));
|
||||
|
||||
recalculateWidths = false;
|
||||
//LOGGER.info("new dimension width in regions: " + newWidth + "\t potential: " + newWidth );
|
||||
@@ -368,6 +383,7 @@ public class ClientProxy
|
||||
/** this method reset some static data every time we change world */
|
||||
private void resetMod()
|
||||
{
|
||||
// TODO when should this be used?
|
||||
ThreadMapUtil.clearMaps();
|
||||
LodGenWorker.restartExecutorService();
|
||||
|
||||
|
||||
@@ -21,11 +21,16 @@ package com.seibel.lod.proxy;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.lod.ModInfo;
|
||||
import com.seibel.lod.enums.GlProxyContext;
|
||||
import com.seibel.lod.render.shader.LodShader;
|
||||
import com.seibel.lod.render.shader.LodShaderProgram;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
/**
|
||||
@@ -40,29 +45,31 @@ import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br><br>
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-23-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class GlProxy
|
||||
{
|
||||
private static GlProxy instance = null;
|
||||
|
||||
private static final MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
private static MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
|
||||
|
||||
/** Minecraft's GLFW window */
|
||||
public final long minecraftGlContext;
|
||||
/** Minecraft's GL context */
|
||||
/** Minecraft's GL capabilities */
|
||||
public final GLCapabilities minecraftGlCapabilities;
|
||||
|
||||
/** the LodBuilder's GLFW window */
|
||||
public final long lodBuilderGlContext;
|
||||
/** the LodBuilder's GL context */
|
||||
/** the LodBuilder's GL capabilities */
|
||||
public final GLCapabilities lodBuilderGlCapabilities;
|
||||
|
||||
/**
|
||||
* This is just used for debugging, hopefully it can be removed once
|
||||
* the context switching is more stable.
|
||||
*/
|
||||
public Thread lodBuilderOwnerThread = null;
|
||||
|
||||
/** This program contains all shaders required when rendering LODs */
|
||||
public LodShaderProgram lodShaderProgram;
|
||||
/** This is the VAO that is used when rendering */
|
||||
public final int vertexArrayObjectId;
|
||||
|
||||
|
||||
/** Does this computer's GPU support fancy fog? */
|
||||
public final boolean fancyFogAvailable;
|
||||
@@ -74,6 +81,8 @@ public class GlProxy
|
||||
public final boolean mapBufferRangeSupported;
|
||||
|
||||
|
||||
|
||||
|
||||
private GlProxy()
|
||||
{
|
||||
ClientProxy.LOGGER.error("Creating " + GlProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error.");
|
||||
@@ -93,54 +102,58 @@ public class GlProxy
|
||||
minecraftGlContext = GLFW.glfwGetCurrentContext();
|
||||
minecraftGlCapabilities = GL.getCapabilities();
|
||||
|
||||
// create the LodBuilder's context
|
||||
|
||||
// Hopefully this shouldn't cause any issues with other mods that need custom contexts
|
||||
// (although the number that do should be relatively few)
|
||||
// context creation setup
|
||||
GLFW.glfwDefaultWindowHints();
|
||||
// make the context window invisible
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
||||
// by default the context should get the highest available OpenGL version
|
||||
// but this can be explicitly set for testing
|
||||
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
|
||||
// create an invisible window to hold the context
|
||||
lodBuilderGlContext = GLFW.glfwCreateWindow(640, 480, "LOD window", 0L, minecraftGlContext);
|
||||
|
||||
// create the LodBuilder context
|
||||
lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, minecraftGlContext);
|
||||
GLFW.glfwMakeContextCurrent(lodBuilderGlContext);
|
||||
lodBuilderGlCapabilities = GL.createCapabilities();
|
||||
|
||||
// Since this is called on the render thread, make sure the Minecraft context is used in the end
|
||||
GLFW.glfwMakeContextCurrent(minecraftGlContext);
|
||||
GL.setCapabilities(minecraftGlCapabilities);
|
||||
|
||||
|
||||
|
||||
|
||||
//==============================//
|
||||
// determine the OpenGL version //
|
||||
//==============================//
|
||||
|
||||
bufferStorageSupported = minecraftGlCapabilities.OpenGL45;
|
||||
mapBufferRangeSupported = minecraftGlCapabilities.OpenGL30;
|
||||
|
||||
if (!minecraftGlCapabilities.OpenGL15)
|
||||
{
|
||||
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GlProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 1.5 or greater.";
|
||||
mc.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 1.5 or greater."));
|
||||
}
|
||||
|
||||
if (!bufferStorageSupported)
|
||||
{
|
||||
String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5";
|
||||
|
||||
ClientProxy.LOGGER.error("This GPU doesn't support OpenGL 4.5, falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//==================================//
|
||||
// get any GPU related capabilities //
|
||||
//==================================//
|
||||
|
||||
// see if this GPU can run fancy fog
|
||||
fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance;
|
||||
ClientProxy.LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "].");
|
||||
|
||||
// crash the game if the GPU doesn't support OpenGL 2.0
|
||||
if (!minecraftGlCapabilities.OpenGL20)
|
||||
{
|
||||
// Note: as of MC 1.17 this shouldn't happen since MC
|
||||
// requires OpenGL 3.3, but just in case.
|
||||
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GlProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 2.0 or greater.";
|
||||
mc.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 2.0 or greater."));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get specific capabilities
|
||||
// TODO re-add buffer storage support
|
||||
bufferStorageSupported = false; //lodBuilderGlCapabilities.glBufferStorage != 0;
|
||||
mapBufferRangeSupported = lodBuilderGlCapabilities.glMapBufferRange != 0;
|
||||
fancyFogAvailable = minecraftGlCapabilities.GL_NV_fog_distance;
|
||||
|
||||
|
||||
// display the capabilities
|
||||
if (!bufferStorageSupported)
|
||||
{
|
||||
String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5";
|
||||
ClientProxy.LOGGER.error("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance.");
|
||||
}
|
||||
|
||||
if (!fancyFogAvailable)
|
||||
ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that the fancy fog option will not be available.");
|
||||
@@ -148,11 +161,79 @@ public class GlProxy
|
||||
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// shader setup //
|
||||
//==============//
|
||||
|
||||
//setGlContext(GlProxyContext.LOD_RENDER);
|
||||
setGlContext(GlProxyContext.MINECRAFT);
|
||||
|
||||
createShaderProgram();
|
||||
|
||||
|
||||
// Note: VAO objects can not be shared between contexts,
|
||||
// this must be created on the LOD render context to work correctly
|
||||
vertexArrayObjectId = GL30.glGenVertexArrays();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// clean up //
|
||||
//==========//
|
||||
|
||||
// Since this is created on the render thread, make sure the Minecraft context is used in the end
|
||||
setGlContext(GlProxyContext.MINECRAFT);
|
||||
|
||||
|
||||
// GlProxy creation success
|
||||
ClientProxy.LOGGER.error(GlProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
|
||||
}
|
||||
|
||||
|
||||
/** Creates all required shaders */
|
||||
public void createShaderProgram()
|
||||
{
|
||||
LodShader vertexShader = null;
|
||||
LodShader fragmentShader = null;
|
||||
|
||||
try
|
||||
{
|
||||
// get the shaders from the resource folder
|
||||
vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "shaders/unshaded.vert", false);
|
||||
fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "shaders/unshaded.frag", false);
|
||||
|
||||
// this can be used when testing shaders,
|
||||
// since we can't hot swap the files in the resource folder
|
||||
// vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "C:/Users/James Seibel/Desktop/shaders/unshaded.vert", true);
|
||||
// fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "C:/Users/James Seibel/Desktop/shaders/unshaded.frag", true);
|
||||
|
||||
|
||||
// create the shaders
|
||||
|
||||
lodShaderProgram = new LodShaderProgram();
|
||||
|
||||
// Attach the compiled shaders to the program
|
||||
lodShaderProgram.attachShader(vertexShader);
|
||||
lodShaderProgram.attachShader(fragmentShader);
|
||||
|
||||
// activate the fragment shader output
|
||||
GL30.glBindFragDataLocation(lodShaderProgram.id, 0, "fragColor");
|
||||
|
||||
// attach the shader program to the OpenGL context
|
||||
lodShaderProgram.link();
|
||||
|
||||
// after the shaders have been attached to the program
|
||||
// we don't need their OpenGL references anymore
|
||||
GL20.glDeleteShader(vertexShader.id);
|
||||
GL20.glDeleteShader(fragmentShader.id);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ClientProxy.LOGGER.error("Unable to compile shaders. Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -163,12 +244,12 @@ public class GlProxy
|
||||
{
|
||||
GlProxyContext currentContext = getGlContext();
|
||||
|
||||
// we don't have to change the context, we're already there.
|
||||
// we don't have to change the context, we are already there.
|
||||
if (currentContext == newContext)
|
||||
return;
|
||||
|
||||
|
||||
long contextPointer = 0L;
|
||||
long contextPointer;
|
||||
GLCapabilities newGlCapabilities = null;
|
||||
|
||||
// get the pointer(s) for this context
|
||||
@@ -187,20 +268,13 @@ public class GlProxy
|
||||
default: // default should never happen, it is just here to make the compiler happy
|
||||
case NONE:
|
||||
// 0L is equivalent to null
|
||||
contextPointer = 0L;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
GLFW.glfwMakeContextCurrent(contextPointer);
|
||||
GL.setCapabilities(newGlCapabilities);
|
||||
|
||||
|
||||
|
||||
// used for debugging
|
||||
if (newContext == GlProxyContext.LOD_BUILDER)
|
||||
lodBuilderOwnerThread = Thread.currentThread();
|
||||
else if (newContext == GlProxyContext.NONE && currentContext == GlProxyContext.LOD_BUILDER)
|
||||
lodBuilderOwnerThread = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,9 +294,12 @@ public class GlProxy
|
||||
else if (currentContext == 0L)
|
||||
return GlProxyContext.NONE;
|
||||
else
|
||||
// hopefully this shouldn't happen, but
|
||||
// at least now we will be notified if it does happen
|
||||
throw new IllegalStateException(Thread.currentThread().getName() + " has a unknown OpenGl context: [" + currentContext + "]. Minecraft context [" + minecraftGlContext + "], LodBuilder context [" + lodBuilderGlContext + "], no context [0].");
|
||||
// hopefully this shouldn't happen
|
||||
throw new IllegalStateException(Thread.currentThread().getName() +
|
||||
" has a unknown OpenGl context: [" + currentContext + "]. "
|
||||
+ "Minecraft context [" + minecraftGlContext + "], "
|
||||
+ "LodBuilder context [" + lodBuilderGlContext + "], "
|
||||
+ "no context [0].");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,44 +19,52 @@
|
||||
|
||||
package com.seibel.lod.render;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.NVFogDistance;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder;
|
||||
import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder.VertexBuffersAndOffset;
|
||||
import com.seibel.lod.config.LodConfig;
|
||||
import com.seibel.lod.enums.*;
|
||||
import com.seibel.lod.enums.DebugMode;
|
||||
import com.seibel.lod.enums.FogDistance;
|
||||
import com.seibel.lod.enums.FogDrawOverride;
|
||||
import com.seibel.lod.enums.FogQuality;
|
||||
import com.seibel.lod.enums.GpuUploadMethod;
|
||||
import com.seibel.lod.handlers.ReflectionHandler;
|
||||
import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.objects.NearFarFogSettings;
|
||||
import com.seibel.lod.objects.RegionPos;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.proxy.GlProxy;
|
||||
import com.seibel.lod.render.shader.LodShaderProgram;
|
||||
import com.seibel.lod.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.util.LevelPosUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
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.vector.Matrix4f;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL15C;
|
||||
import org.lwjgl.opengl.NVFogDistance;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import net.minecraft.util.math.vector.Vector3f;
|
||||
|
||||
/**
|
||||
* This is where all the magic happens. <br>
|
||||
* This is where LODs are draw to the world.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-25-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodRenderer
|
||||
{
|
||||
@@ -90,7 +98,7 @@ public class LodRenderer
|
||||
*/
|
||||
private int[][][] storageBufferIds;
|
||||
|
||||
private ChunkPos vbosCenter = new ChunkPos(0, 0);
|
||||
private ChunkPosWrapper vbosCenter = new ChunkPosWrapper(0, 0);
|
||||
|
||||
|
||||
/** This is used to determine if the LODs should be regenerated */
|
||||
@@ -124,8 +132,6 @@ public class LodRenderer
|
||||
public boolean vanillaRenderedChunksEmptySkip = false;
|
||||
public int vanillaBlockRenderedDistance;
|
||||
|
||||
final boolean vivecraftDetected = ReflectionHandler.INSTANCE.detectVivecraft();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -147,11 +153,11 @@ public class LodRenderer
|
||||
* Besides drawing the LODs this method also starts
|
||||
* the async process of generating the Buffers that hold those LODs.
|
||||
* @param lodDim The dimension to draw, if null doesn't replace the current dimension.
|
||||
* @param mcMatrixStack This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method
|
||||
* @param mcModelViewMatrix This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method
|
||||
* @param mcProjectionMatrix
|
||||
* @param partialTicks how far into the current tick this method was called.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void drawLODs(LodDimension lodDim, MatrixStack mcMatrixStack, float partialTicks, IProfiler newProfiler)
|
||||
public void drawLODs(LodDimension lodDim, MatrixStack mcModelViewMatrix, Matrix4f mcProjectionMatrix, float partialTicks, IProfiler newProfiler)
|
||||
{
|
||||
//=================================//
|
||||
// determine if LODs should render //
|
||||
@@ -176,14 +182,6 @@ public class LodRenderer
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// initial setup //
|
||||
//===============//
|
||||
|
||||
profiler = newProfiler;
|
||||
profiler.push("LOD setup");
|
||||
|
||||
|
||||
// TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead)
|
||||
// starting here...
|
||||
determineIfLodsShouldRegenerate(lodDim, partialTicks);
|
||||
@@ -197,25 +195,17 @@ public class LodRenderer
|
||||
// 2. we aren't already regenerating the LODs
|
||||
// 3. we aren't waiting for the build and draw buffers to swap
|
||||
// (this is to prevent thread conflicts)
|
||||
if (LodConfig.CLIENT.advancedModOptions.debugging.drawLods.get())
|
||||
if ((partialRegen || fullRegen) && !lodBufferBuilder.generatingBuffers && !lodBufferBuilder.newBuffersAvailable())
|
||||
{
|
||||
if (lodBufferBuilder.buildableBuffers == null)
|
||||
lodBufferBuilder.setupBuffers(lodDim);
|
||||
// generate the LODs on a separate thread to prevent stuttering or freezing
|
||||
lodBufferBuilder.generateLodBuffersAsync(this, lodDim, mc.getPlayerBlockPos(), true);
|
||||
|
||||
if ((partialRegen || fullRegen) && !lodBufferBuilder.generatingBuffers && !lodBufferBuilder.newBuffersAvailable())
|
||||
{
|
||||
// generate the LODs on a separate thread to prevent stuttering or freezing
|
||||
lodBufferBuilder.generateLodBuffersAsync(this, lodDim, mc.getPlayer().blockPosition(), fullRegen);
|
||||
|
||||
// the regen process has been started,
|
||||
// it will be done when lodBufferBuilder.newBuffersAvailable()
|
||||
// is true
|
||||
fullRegen = false;
|
||||
partialRegen = false;
|
||||
}
|
||||
// the regen process has been started,
|
||||
// it will be done when lodBufferBuilder.newBuffersAvailable()
|
||||
// is true
|
||||
fullRegen = false;
|
||||
partialRegen = false;
|
||||
}
|
||||
else
|
||||
lodBufferBuilder.destroyBuffers();
|
||||
|
||||
// TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead)
|
||||
// ...ending here
|
||||
@@ -226,9 +216,19 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
|
||||
//===========================//
|
||||
// GL settings for rendering //
|
||||
//===========================//
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// initial setup //
|
||||
//===============//
|
||||
|
||||
profiler = newProfiler;
|
||||
profiler.push("LOD setup");
|
||||
|
||||
GlProxy glProxy = GlProxy.getInstance();
|
||||
|
||||
|
||||
|
||||
// set the required open GL settings
|
||||
|
||||
@@ -237,49 +237,47 @@ public class LodRenderer
|
||||
else
|
||||
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL);
|
||||
|
||||
GL15.glDisable(GL15.GL_TEXTURE_2D);
|
||||
GL15.glEnable(GL15.GL_CULL_FACE);
|
||||
GL15.glEnable(GL15.GL_COLOR_MATERIAL);
|
||||
GL15.glEnable(GL15.GL_DEPTH_TEST);
|
||||
|
||||
// enable transparent rendering
|
||||
GL15.glBlendFunc(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL15.glEnable(GL15.GL_BLEND);
|
||||
|
||||
// disable the lights Minecraft uses
|
||||
GL15.glDisable(GL15.GL_LIGHT0);
|
||||
GL15.glDisable(GL15.GL_LIGHT1);
|
||||
// get MC's shader program
|
||||
int currentProgram = GL20.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||
|
||||
// get the default projection matrix, so we can
|
||||
// reset it after drawing the LODs
|
||||
float[] mcProjMatrixRaw = new float[16];
|
||||
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
|
||||
Matrix4f mcProjectionMatrix = new Matrix4f(mcProjMatrixRaw);
|
||||
// OpenGl outputs their matrices in col,row form instead of row,col
|
||||
// (or maybe vice versa I have no idea :P)
|
||||
mcProjectionMatrix.transpose();
|
||||
|
||||
Matrix4f modelViewMatrix = offsetTheModelViewMatrix(mcMatrixStack, partialTicks);
|
||||
Matrix4f modelViewMatrix = offsetTheModelViewMatrix(mcModelViewMatrix, partialTicks);
|
||||
vanillaBlockRenderedDistance = mc.getRenderDistance() * LodUtil.CHUNK_WIDTH;
|
||||
// required for setupFog and setupProjectionMatrix
|
||||
if (mc.getClientWorld().dimensionType().hasCeiling())
|
||||
if (mc.getClientLevel().dimensionType().hasCeiling())
|
||||
farPlaneBlockDistance = Math.min(LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * LodUtil.CHUNK_WIDTH;
|
||||
else
|
||||
farPlaneBlockDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
|
||||
|
||||
setupProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, partialTicks);
|
||||
|
||||
Matrix4f projectionMatrix = createProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, partialTicks);
|
||||
|
||||
|
||||
// commented out until we can add shaders to handle lighting
|
||||
//setupLighting(lodDim, partialTicks);
|
||||
|
||||
NearFarFogSettings fogSettings = determineFogSettings();
|
||||
|
||||
// determine the current fog settings, so they can be
|
||||
// reset after drawing the LODs
|
||||
float defaultFogStartDist = GL15.glGetFloat(GL15.GL_FOG_START);
|
||||
float defaultFogEndDist = GL15.glGetFloat(GL15.GL_FOG_END);
|
||||
int defaultFogMode = GL15.glGetInteger(GL15.GL_FOG_MODE);
|
||||
int defaultFogDistance = GlProxy.getInstance().fancyFogAvailable ? GL15.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV) : -1;
|
||||
// // determine the current fog settings, so they can be
|
||||
// // reset after drawing the LODs
|
||||
// float defaultFogStartDist = GL15.glGetFloat(GL15.GL_FOG_START);
|
||||
// float defaultFogEndDist = GL15.glGetFloat(GL15.GL_FOG_END);
|
||||
// int defaultFogMode = GL15.glGetInteger(GL15.GL_FOG_MODE);
|
||||
// int defaultFogDistance = glProxy.fancyFogAvailable ? GL15.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV) : -1;
|
||||
|
||||
//ShaderInstance mcShader = RenderSystem.getShader();
|
||||
|
||||
// NearFarFogSettings fogSettings = determineFogSettings();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
@@ -287,13 +285,14 @@ public class LodRenderer
|
||||
|
||||
profiler.popPush("LOD draw");
|
||||
|
||||
if (vbos != null && LodConfig.CLIENT.advancedModOptions.debugging.drawLods.get())
|
||||
if (vbos != null)
|
||||
{
|
||||
ActiveRenderInfo renderInfo = mc.getGameRenderer().getMainCamera();
|
||||
Vector3d cameraDir = new Vector3d(renderInfo.getLookVector());
|
||||
ActiveRenderInfo camera = mc.getGameRenderer().getMainCamera();
|
||||
Vector3f cameraDir = camera.getLookVector();
|
||||
|
||||
boolean cullingDisabled = LodConfig.CLIENT.graphics.advancedGraphicsOption.disableDirectionalCulling.get();
|
||||
boolean renderBufferStorage = LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.get() == GpuUploadMethod.BUFFER_STORAGE && GlProxy.getInstance().bufferStorageSupported;
|
||||
// TODO re-enable once rendering is totally working
|
||||
boolean cullingDisabled = true; //LodConfig.CLIENT.graphics.advancedGraphicsOption.disableDirectionalCulling.get();
|
||||
boolean renderBufferStorage = LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.get() == GpuUploadMethod.BUFFER_STORAGE && glProxy.bufferStorageSupported;
|
||||
|
||||
// used to determine what type of fog to render
|
||||
int halfWidth = vbos.length / 2;
|
||||
@@ -303,6 +302,32 @@ public class LodRenderer
|
||||
RegionPos vboCenterRegionPos = new RegionPos(vbosCenter);
|
||||
|
||||
|
||||
|
||||
|
||||
// can be used when testing shaders
|
||||
//glProxy.createShaderProgram();
|
||||
|
||||
|
||||
LodShaderProgram shaderProgram = glProxy.lodShaderProgram;
|
||||
shaderProgram.use();
|
||||
|
||||
|
||||
// determine the VertexArrayObject's element positions
|
||||
int posAttrib = shaderProgram.getAttributeLocation("vPosition");
|
||||
shaderProgram.enableVertexAttribute(posAttrib);
|
||||
int colAttrib = shaderProgram.getAttributeLocation("color");
|
||||
shaderProgram.enableVertexAttribute(colAttrib);
|
||||
|
||||
|
||||
|
||||
// upload the required uniforms
|
||||
int mvmUniform = shaderProgram.getUniformLocation("modelViewMatrix");
|
||||
shaderProgram.setUniform(mvmUniform, modelViewMatrix);
|
||||
int projUniform = shaderProgram.getUniformLocation("projectionMatrix");
|
||||
shaderProgram.setUniform(projUniform, projectionMatrix);
|
||||
|
||||
|
||||
// render each of the buffers
|
||||
for (int x = 0; x < vbos.length; x++)
|
||||
{
|
||||
for (int z = 0; z < vbos.length; z++)
|
||||
@@ -311,27 +336,34 @@ public class LodRenderer
|
||||
x + vboCenterRegionPos.x - (lodDim.getWidth() / 2),
|
||||
z + vboCenterRegionPos.z - (lodDim.getWidth() / 2));
|
||||
|
||||
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(renderInfo.getBlockPosition(), cameraDir, vboPos.blockPos()))
|
||||
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(camera.getBlockPosition(), cameraDir, vboPos.blockPos()))
|
||||
{
|
||||
if ((x > halfWidth - quarterWidth && x < halfWidth + quarterWidth)
|
||||
&& (z > halfWidth - quarterWidth && z < halfWidth + quarterWidth))
|
||||
setupFog(fogSettings.near.distance, fogSettings.near.quality);
|
||||
else
|
||||
setupFog(fogSettings.far.distance, fogSettings.far.quality);
|
||||
// TODO add fog to the fragment shader
|
||||
// if ((x > halfWidth - quarterWidth && x < halfWidth + quarterWidth)
|
||||
// && (z > halfWidth - quarterWidth && z < halfWidth + quarterWidth))
|
||||
// setupFog(fogSettings.near.distance, fogSettings.near.quality);
|
||||
// else
|
||||
// setupFog(fogSettings.far.distance, fogSettings.far.quality);
|
||||
|
||||
|
||||
if (storageBufferIds != null && renderBufferStorage)
|
||||
for (int i = 0; i < storageBufferIds[x][z].length; i++)
|
||||
drawStorageBuffer(vbos[x][z][i], storageBufferIds[x][z][i], modelViewMatrix);
|
||||
else
|
||||
// if (storageBufferIds != null && renderBufferStorage)
|
||||
// for (int i = 0; i < storageBufferIds[x][z].length; i++)
|
||||
// drawArrays(storageBufferIds[x][z][i], vbos[x][z][i].vertexCount, posAttrib, colAttrib);
|
||||
// else
|
||||
for (int i = 0; i < vbos[x][z].length; i++)
|
||||
drawVertexBuffer(vbos[x][z][i], modelViewMatrix);
|
||||
drawArrays(vbos[x][z][i].id, vbos[x][z][i].vertexCount, posAttrib, colAttrib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GL20.glDisableVertexAttribArray(posAttrib);
|
||||
GL20.glDisableVertexAttribArray(colAttrib);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// cleanup //
|
||||
//=========//
|
||||
@@ -339,23 +371,12 @@ public class LodRenderer
|
||||
profiler.popPush("LOD cleanup");
|
||||
|
||||
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL);
|
||||
GL15.glEnable(GL15.GL_TEXTURE_2D);
|
||||
GL15.glDisable(LOD_GL_LIGHT_NUMBER);
|
||||
GL15.glDisable(GL15.GL_BLEND);
|
||||
// re-enable the lights Minecraft uses
|
||||
GL15.glEnable(GL15.GL_LIGHT0);
|
||||
GL15.glEnable(GL15.GL_LIGHT1);
|
||||
RenderSystem.disableLighting();
|
||||
GL15.glDisable(GL15.GL_BLEND); // TODO: what should this be reset to?
|
||||
|
||||
// reset the fog settings so the normal chunks
|
||||
// will be drawn correctly
|
||||
cleanupFog(fogSettings, defaultFogStartDist, defaultFogEndDist, defaultFogMode, defaultFogDistance);
|
||||
GL20.glUseProgram(currentProgram);
|
||||
//RenderSystem.setShader(() -> mcShader);
|
||||
|
||||
// reset the projection matrix so anything drawn after
|
||||
// the LODs will use the correct projection matrix
|
||||
gameRender.resetProjectionMatrix(mcProjectionMatrix);
|
||||
|
||||
// clear the depth buffer so anything drawn is drawn
|
||||
// clear the depth buffer so everything drawn is drawn
|
||||
// over the LODs
|
||||
GL15.glClear(GL15.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
@@ -364,40 +385,40 @@ public class LodRenderer
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
|
||||
/** This is where the actual drawing happens. */
|
||||
private void drawStorageBuffer(VertexBuffer vbo, int bufferStorageId, Matrix4f modelViewMatrix)
|
||||
private void drawArrays(int glBufferId, int vertexCount, int posAttrib, int colAttrib)
|
||||
{
|
||||
if (vbo == null)
|
||||
if (glBufferId == 0)
|
||||
return;
|
||||
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferStorageId);
|
||||
// 0L is the starting pointer
|
||||
LodUtil.LOD_VERTEX_FORMAT.setupBufferState(0L);
|
||||
// can be used to check for OpenGL errors
|
||||
// int error = GL15.glGetError();
|
||||
// ClientProxy.LOGGER.info(Integer.toHexString(error));
|
||||
|
||||
vbo.draw(modelViewMatrix, GL15.GL_QUADS);
|
||||
|
||||
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
LodUtil.LOD_VERTEX_FORMAT.clearBufferState();
|
||||
// bind the buffer we are going to draw
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, glBufferId);
|
||||
GL30.glBindVertexArray(GlProxy.getInstance().vertexArrayObjectId);
|
||||
|
||||
// let OpenGL know how our buffer is set up
|
||||
int vertexByteCount = (Float.BYTES * 3) + (Byte.BYTES * 4);
|
||||
GL20.glEnableVertexAttribArray(posAttrib);
|
||||
GL20.glVertexAttribPointer(posAttrib, 3, GL15.GL_FLOAT, false, vertexByteCount, 0);
|
||||
GL20.glEnableVertexAttribArray(colAttrib);
|
||||
GL20.glVertexAttribPointer(colAttrib, 4, GL15.GL_UNSIGNED_BYTE, true, vertexByteCount, Float.BYTES * 3);
|
||||
|
||||
// draw the LODs
|
||||
GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, vertexCount);
|
||||
|
||||
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GL30.glBindVertexArray(0);
|
||||
|
||||
GL20.glDisableVertexAttribArray(posAttrib);
|
||||
GL20.glDisableVertexAttribArray(colAttrib);
|
||||
}
|
||||
|
||||
|
||||
/** This is where the actual drawing happens. */
|
||||
private void drawVertexBuffer(VertexBuffer vbo, Matrix4f modelViewMatrix)
|
||||
{
|
||||
if (vbo == null)
|
||||
return;
|
||||
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id);
|
||||
// 0L is the starting pointer
|
||||
LodUtil.LOD_VERTEX_FORMAT.setupBufferState(0L);
|
||||
|
||||
vbo.draw(modelViewMatrix, GL15.GL_QUADS);
|
||||
|
||||
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
LodUtil.LOD_VERTEX_FORMAT.clearBufferState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -405,7 +426,6 @@ public class LodRenderer
|
||||
// Setup Functions //
|
||||
//=================//
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void setupFog(FogDistance fogDistance, FogQuality fogQuality)
|
||||
{
|
||||
if (fogQuality == FogQuality.OFF)
|
||||
@@ -445,55 +465,52 @@ public class LodRenderer
|
||||
{
|
||||
// for more realistic fog when using FAR
|
||||
if (LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.get() == FogDistance.NEAR_AND_FAR)
|
||||
RenderSystem.fogStart(farPlaneBlockDistance * 1.6f * 0.9f);
|
||||
GL15.glFogf(GL15.GL_FOG_START, farPlaneBlockDistance * 1.6f * 0.9f);
|
||||
else
|
||||
RenderSystem.fogStart(Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f * 1.6f));
|
||||
RenderSystem.fogEnd(farPlaneBlockDistance * 1.6f);
|
||||
GL15.glFogf(GL15.GL_FOG_START, Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f * 1.6f));
|
||||
GL15.glFogf(GL15.GL_FOG_END, farPlaneBlockDistance * 1.6f);
|
||||
}
|
||||
else if (fogQuality == FogQuality.FAST)
|
||||
{
|
||||
// for the far fog of the normal chunks
|
||||
// to start right where the LODs' end use:
|
||||
// end = 0.8f, start = 1.5f
|
||||
RenderSystem.fogStart(farPlaneBlockDistance * 0.75f);
|
||||
RenderSystem.fogEnd(farPlaneBlockDistance * 1.0f);
|
||||
GL15.glFogf(GL15.GL_FOG_START, farPlaneBlockDistance * 0.75f);
|
||||
GL15.glFogf(GL15.GL_FOG_END, farPlaneBlockDistance * 1.0f);
|
||||
}
|
||||
}
|
||||
else if (fogDistance == FogDistance.NEAR)
|
||||
{
|
||||
if (fogQuality == FogQuality.FANCY)
|
||||
{
|
||||
RenderSystem.fogEnd(vanillaBlockRenderedDistance * 1.41f);
|
||||
RenderSystem.fogStart(vanillaBlockRenderedDistance * 1.6f);
|
||||
GL15.glFogf(GL15.GL_FOG_END, vanillaBlockRenderedDistance * 1.41f);
|
||||
GL15.glFogf(GL15.GL_FOG_START, vanillaBlockRenderedDistance * 1.6f);
|
||||
}
|
||||
else if (fogQuality == FogQuality.FAST)
|
||||
{
|
||||
RenderSystem.fogEnd(vanillaBlockRenderedDistance * 1.0f);
|
||||
RenderSystem.fogStart(vanillaBlockRenderedDistance * 1.5f);
|
||||
GL15.glFogf(GL15.GL_FOG_END, vanillaBlockRenderedDistance * 1.0f);
|
||||
GL15.glFogf(GL15.GL_FOG_START, vanillaBlockRenderedDistance * 1.5f);
|
||||
}
|
||||
}
|
||||
|
||||
GL15.glEnable(GL15.GL_FOG);
|
||||
RenderSystem.enableFog();
|
||||
RenderSystem.setupNvFogDistance();
|
||||
RenderSystem.fogMode(GlStateManager.FogMode.LINEAR);
|
||||
GL15.glFogi(GL15.GL_FOG_MODE, GL15.GL_LINEAR);
|
||||
|
||||
if (GlProxy.getInstance().fancyFogAvailable)
|
||||
GL15.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, glFogDistanceMode);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Revert any changes that were made to the fog
|
||||
* and sets up the fog for Minecraft.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private void cleanupFog(NearFarFogSettings fogSettings,
|
||||
float defaultFogStartDist, float defaultFogEndDist,
|
||||
int defaultFogMode, int defaultFogDistance)
|
||||
{
|
||||
RenderSystem.fogStart(defaultFogStartDist);
|
||||
RenderSystem.fogEnd(defaultFogEndDist);
|
||||
RenderSystem.fogMode(defaultFogMode);
|
||||
GL15.glFogf(GL15.GL_FOG_START, defaultFogStartDist);
|
||||
GL15.glFogf(GL15.GL_FOG_END, defaultFogEndDist);
|
||||
GL15.glFogi(GL15.GL_FOG_MODE, defaultFogMode);
|
||||
|
||||
// this setting is only valid if the GPU supports fancy fog
|
||||
if (GlProxy.getInstance().fancyFogAvailable)
|
||||
@@ -502,7 +519,7 @@ public class LodRenderer
|
||||
// disable fog if Minecraft wasn't rendering fog
|
||||
// or we want it disabled
|
||||
if (!fogSettings.vanillaIsRenderingFog
|
||||
|| LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.get())
|
||||
|| LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.get())
|
||||
{
|
||||
// Make fog render a infinite distance away.
|
||||
// This doesn't technically disable Minecraft's fog
|
||||
@@ -512,9 +529,9 @@ public class LodRenderer
|
||||
// we can't disable minecraft's fog outright because by default
|
||||
// minecraft will re-enable the fog after our code
|
||||
|
||||
RenderSystem.fogStart(0.0F);
|
||||
RenderSystem.fogEnd(Float.MAX_VALUE);
|
||||
RenderSystem.fogDensity(0.0F);
|
||||
GL15.glFogf(GL15.GL_FOG_START, 0.0F);
|
||||
GL15.glFogf(GL15.GL_FOG_END, Float.MAX_VALUE);
|
||||
GL15.glFogf(GL15.GL_FOG_DENSITY, Float.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,87 +543,72 @@ public class LodRenderer
|
||||
* (since AxisAlignedBoundingBoxes (LODs) use doubles and thus have a higher
|
||||
* accuracy vs the model view matrix, which only uses floats)
|
||||
*/
|
||||
private Matrix4f offsetTheModelViewMatrix(MatrixStack mcMatrixStack, float partialTicks)
|
||||
private Matrix4f offsetTheModelViewMatrix(MatrixStack mcModelViewMatrix, float partialTicks)
|
||||
{
|
||||
// duplicate the last matrix
|
||||
mcMatrixStack.pushPose();
|
||||
mcModelViewMatrix.pushPose();
|
||||
|
||||
|
||||
// get all relevant camera info
|
||||
ActiveRenderInfo renderInfo = mc.getGameRenderer().getMainCamera();
|
||||
Vector3d projectedView = renderInfo.getPosition();
|
||||
ActiveRenderInfo camera = mc.getGameRenderer().getMainCamera();
|
||||
Vector3d projectedView = camera.getPosition();
|
||||
|
||||
// translate the camera relative to the regions' center
|
||||
// (AxisAlignedBoundingBoxes (LODs) use doubles and thus have a higher
|
||||
// accuracy vs the model view matrix, which only uses floats)
|
||||
BlockPos bufferPos = vbosCenter.getWorldPosition();
|
||||
BlockPosWrapper bufferPos = vbosCenter.getWorldPosition();
|
||||
double xDiff = projectedView.x - bufferPos.getX();
|
||||
double zDiff = projectedView.z - bufferPos.getZ();
|
||||
mcMatrixStack.translate(-xDiff, -projectedView.y, -zDiff);
|
||||
mcModelViewMatrix.translate(-xDiff, -projectedView.y, -zDiff);
|
||||
|
||||
|
||||
|
||||
// get the modified model view matrix
|
||||
Matrix4f lodModelViewMatrix = mcMatrixStack.last().pose();
|
||||
Matrix4f lodModelViewMatrix = mcModelViewMatrix.last().pose();
|
||||
// remove the lod ModelViewMatrix
|
||||
mcMatrixStack.popPose();
|
||||
mcModelViewMatrix.popPose();
|
||||
|
||||
return lodModelViewMatrix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create a new projection matrix and send it over to the GPU
|
||||
* create and return a new projection matrix based on MC's projection matrix
|
||||
* @param currentProjectionMatrix this is Minecraft's current projection matrix
|
||||
* @param vanillaBlockRenderedDistance Minecraft's vanilla far plane distance
|
||||
* @param partialTicks how many ticks into the frame we are
|
||||
*/
|
||||
private void setupProjectionMatrix(Matrix4f currentProjectionMatrix, float vanillaBlockRenderedDistance, float partialTicks)
|
||||
private Matrix4f createProjectionMatrix(Matrix4f currentProjectionMatrix, float vanillaBlockRenderedDistance, float partialTicks)
|
||||
{
|
||||
Matrix4f lodPoj;
|
||||
float nearClipPlane = LodConfig.CLIENT.graphics.advancedGraphicsOption.useExtendedNearClipPlane.get() ? vanillaBlockRenderedDistance / 5 : 1;
|
||||
float farClipPlane = farPlaneBlockDistance * LodUtil.CHUNK_WIDTH >> 1;
|
||||
// create the new projection matrix
|
||||
Matrix4f lodProj =
|
||||
Matrix4f.perspective(
|
||||
getFov(partialTicks, true),
|
||||
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
|
||||
LodConfig.CLIENT.graphics.advancedGraphicsOption.useExtendedNearClipPlane.get() ? vanillaBlockRenderedDistance / 5 : 1,
|
||||
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH / 2);
|
||||
|
||||
if (vivecraftDetected)
|
||||
{
|
||||
//use modify clip plane method to modify the current projection matrix's clip planes.
|
||||
lodPoj = ReflectionHandler.INSTANCE.Matrix4fModifyClipPlanes(
|
||||
currentProjectionMatrix,
|
||||
nearClipPlane,
|
||||
farClipPlane);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the new projection matrix
|
||||
lodPoj = Matrix4f.perspective(
|
||||
getFov(partialTicks, true),
|
||||
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
|
||||
nearClipPlane,
|
||||
farClipPlane);
|
||||
|
||||
// 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);
|
||||
}
|
||||
// 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)
|
||||
|
||||
// send the projection over to the GPU
|
||||
gameRender.resetProjectionMatrix(lodPoj);
|
||||
|
||||
// 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)
|
||||
lodProj.multiply(distortionMatrix);
|
||||
|
||||
return lodProj;
|
||||
}
|
||||
|
||||
|
||||
@@ -695,7 +697,7 @@ public class LodRenderer
|
||||
lodBufferBuilder.destroyBuffers();
|
||||
}
|
||||
|
||||
|
||||
// TODO move this into the MC wrapper
|
||||
private double getFov(float partialTicks, boolean useFovSetting)
|
||||
{
|
||||
return mc.getGameRenderer().getFov(mc.getGameRenderer().getMainCamera(), partialTicks, useFovSetting);
|
||||
@@ -804,8 +806,6 @@ public class LodRenderer
|
||||
/** Determines if the LODs should have a fullRegen or partialRegen */
|
||||
private void determineIfLodsShouldRegenerate(LodDimension lodDim, float partialTicks)
|
||||
{
|
||||
|
||||
|
||||
short chunkRenderDistance = (short) mc.getRenderDistance();
|
||||
int vanillaRenderedChunksWidth = chunkRenderDistance * 2 + 2;
|
||||
|
||||
@@ -815,14 +815,14 @@ public class LodRenderer
|
||||
|
||||
// check if the view distance changed
|
||||
if (ClientProxy.previousLodRenderDistance != LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get()
|
||||
|| chunkRenderDistance != prevRenderDistance
|
||||
|| prevFogDistance != LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.get())
|
||||
|| chunkRenderDistance != prevRenderDistance
|
||||
|| prevFogDistance != LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.get())
|
||||
{
|
||||
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
DetailDistanceUtil.updateSettings();
|
||||
fullRegen = true;
|
||||
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
|
||||
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayerChunkPos().getZ(), mc.getPlayerChunkPos().getZ());
|
||||
prevFogDistance = LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.get();
|
||||
prevRenderDistance = chunkRenderDistance;
|
||||
}
|
||||
@@ -841,12 +841,12 @@ public class LodRenderer
|
||||
if (newTime - prevPlayerPosTime > LodConfig.CLIENT.advancedModOptions.buffers.rebuildTimes.get().playerMoveTimeout)
|
||||
{
|
||||
if (LevelPosUtil.getDetailLevel(previousPos) == 0
|
||||
|| mc.getPlayer().xChunk != LevelPosUtil.getPosX(previousPos)
|
||||
|| mc.getPlayer().zChunk != LevelPosUtil.getPosZ(previousPos))
|
||||
|| mc.getPlayerChunkPos().getX() != LevelPosUtil.getPosX(previousPos)
|
||||
|| mc.getPlayerChunkPos().getZ() != LevelPosUtil.getPosZ(previousPos))
|
||||
{
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
fullRegen = true;
|
||||
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
|
||||
previousPos = LevelPosUtil.createLevelPos((byte) 4, mc.getPlayerChunkPos().getX(), mc.getPlayerChunkPos().getZ());
|
||||
}
|
||||
prevPlayerPosTime = newTime;
|
||||
}
|
||||
@@ -875,17 +875,23 @@ public class LodRenderer
|
||||
|
||||
// check if the lighting changed
|
||||
if (Math.abs(skyBrightness - prevSkyBrightness) > minLightingDifference
|
||||
// make sure the lighting gets to the max/minimum value
|
||||
// (just in case the minLightingDifference is too large to notice the change)
|
||||
|| (skyBrightness == 1.0f && prevSkyBrightness != 1.0f) // noon
|
||||
|| (skyBrightness == 0.2f && prevSkyBrightness != 0.2f) // midnight
|
||||
|| mc.getOptions().gamma != prevBrightness)
|
||||
// make sure the lighting gets to the max/minimum value
|
||||
// (just in case the minLightingDifference is too large to notice the change)
|
||||
|| (skyBrightness == 1.0f && prevSkyBrightness != 1.0f) // noon
|
||||
|| (skyBrightness == 0.2f && prevSkyBrightness != 0.2f) // midnight
|
||||
|| mc.getOptions().gamma != prevBrightness)
|
||||
{
|
||||
fullRegen = true;
|
||||
prevBrightness = mc.getOptions().gamma;
|
||||
prevSkyBrightness = skyBrightness;
|
||||
}
|
||||
|
||||
/*if (lightMap != lastLightMap)
|
||||
{
|
||||
fullRegen = true;
|
||||
lastLightMap = lightMap;
|
||||
}*/
|
||||
|
||||
//================//
|
||||
// partial regens //
|
||||
//================//
|
||||
@@ -921,21 +927,21 @@ public class LodRenderer
|
||||
//==============//
|
||||
|
||||
// determine which LODs should not be rendered close to the player
|
||||
HashSet<ChunkPos> chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, mc.getPlayer().blockPosition());
|
||||
HashSet<ChunkPos> chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, mc.getPlayerBlockPos());
|
||||
int xIndex;
|
||||
int zIndex;
|
||||
for (ChunkPos pos : chunkPosToSkip)
|
||||
{
|
||||
vanillaRenderedChunksEmptySkip = false;
|
||||
|
||||
xIndex = (pos.x - mc.getPlayer().xChunk) + (chunkRenderDistance + 1);
|
||||
zIndex = (pos.z - mc.getPlayer().zChunk) + (chunkRenderDistance + 1);
|
||||
xIndex = (pos.x - mc.getPlayerChunkPos().getX()) + (chunkRenderDistance + 1);
|
||||
zIndex = (pos.z - mc.getPlayerChunkPos().getZ()) + (chunkRenderDistance + 1);
|
||||
|
||||
// sometimes we are given chunks that are outside the render distance,
|
||||
// This prevents index out of bounds exceptions
|
||||
if (xIndex >= 0 && zIndex >= 0
|
||||
&& xIndex < vanillaRenderedChunks.length
|
||||
&& zIndex < vanillaRenderedChunks.length)
|
||||
&& xIndex < vanillaRenderedChunks.length
|
||||
&& zIndex < vanillaRenderedChunks.length)
|
||||
{
|
||||
if (!vanillaRenderedChunks[xIndex][zIndex])
|
||||
{
|
||||
@@ -954,6 +960,8 @@ public class LodRenderer
|
||||
vanillaRenderedChunksChanged = true;
|
||||
vanillaRenderedChunksEmptySkip = true;
|
||||
}
|
||||
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,10 +21,11 @@ package com.seibel.lod.render;
|
||||
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.util.math.vector.Vector3f;
|
||||
|
||||
/**
|
||||
* This holds miscellaneous helper code
|
||||
@@ -42,13 +43,13 @@ public class RenderUtil
|
||||
* Returns if the given ChunkPos is in the loaded area of the world.
|
||||
* @param center the center of the loaded world (probably the player's ChunkPos)
|
||||
*/
|
||||
public static boolean isChunkPosInLoadedArea(ChunkPos pos, ChunkPos center)
|
||||
public static boolean isChunkPosInLoadedArea(ChunkPosWrapper pos, ChunkPosWrapper center)
|
||||
{
|
||||
return (pos.x >= center.x - mc.getRenderDistance()
|
||||
&& pos.x <= center.x + mc.getRenderDistance())
|
||||
return (pos.getX() >= center.getX() - mc.getRenderDistance()
|
||||
&& pos.getX() <= center.getX() + mc.getRenderDistance())
|
||||
&&
|
||||
(pos.z >= center.z - mc.getRenderDistance()
|
||||
&& pos.z <= center.z + mc.getRenderDistance());
|
||||
(pos.getZ() >= center.getZ() - mc.getRenderDistance()
|
||||
&& pos.getZ() <= center.getZ() + mc.getRenderDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,22 +86,24 @@ public class RenderUtil
|
||||
* Returns true if one of the region's 4 corners is in front
|
||||
* of the camera.
|
||||
*/
|
||||
public static boolean isRegionInViewFrustum(BlockPos playerBlockPos, Vector3d cameraDir, BlockPos vboCenterPos)
|
||||
public static boolean isRegionInViewFrustum(BlockPos playerBlockPos, Vector3f cameraDir, BlockPosWrapper vboCenterPos)
|
||||
{
|
||||
// convert the vbo position into a direction vector
|
||||
// starting from the player's position
|
||||
Vector3d vboVec = new Vector3d(vboCenterPos.getX(), 0, vboCenterPos.getZ());
|
||||
Vector3d playerVec = new Vector3d(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ());
|
||||
Vector3d vboCenterVec = vboVec.subtract(playerVec);
|
||||
Vector3f vboVec = new Vector3f(vboCenterPos.getX(), 0, vboCenterPos.getZ());
|
||||
Vector3f playerVec = new Vector3f(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ());
|
||||
|
||||
vboVec.sub(playerVec);
|
||||
Vector3f vboCenterVec = vboVec;
|
||||
|
||||
|
||||
int halfRegionWidth = LodUtil.REGION_WIDTH / 2;
|
||||
|
||||
// calculate the 4 corners
|
||||
Vector3d vboSeVec = new Vector3d(vboCenterVec.x + halfRegionWidth, vboCenterVec.y, vboCenterVec.z + halfRegionWidth);
|
||||
Vector3d vboSwVec = new Vector3d(vboCenterVec.x - halfRegionWidth, vboCenterVec.y, vboCenterVec.z + halfRegionWidth);
|
||||
Vector3d vboNwVec = new Vector3d(vboCenterVec.x - halfRegionWidth, vboCenterVec.y, vboCenterVec.z - halfRegionWidth);
|
||||
Vector3d vboNeVec = new Vector3d(vboCenterVec.x + halfRegionWidth, vboCenterVec.y, vboCenterVec.z - halfRegionWidth);
|
||||
Vector3f vboSeVec = new Vector3f(vboCenterVec.x() + halfRegionWidth, vboCenterVec.y(), vboCenterVec.z() + halfRegionWidth);
|
||||
Vector3f vboSwVec = new Vector3f(vboCenterVec.x() - halfRegionWidth, vboCenterVec.y(), vboCenterVec.z() + halfRegionWidth);
|
||||
Vector3f vboNwVec = new Vector3f(vboCenterVec.x() - halfRegionWidth, vboCenterVec.y(), vboCenterVec.z() - halfRegionWidth);
|
||||
Vector3f vboNeVec = new Vector3f(vboCenterVec.x() + halfRegionWidth, vboCenterVec.y(), vboCenterVec.z() - halfRegionWidth);
|
||||
|
||||
// if any corner is visible, this region should be rendered
|
||||
return isNormalizedVectorInViewFrustum(vboSeVec, cameraDir) ||
|
||||
@@ -113,7 +116,7 @@ public class RenderUtil
|
||||
* Currently takes the dot product of the two vectors,
|
||||
* but in the future could do more complicated frustum culling tests.
|
||||
*/
|
||||
private static boolean isNormalizedVectorInViewFrustum(Vector3d objectVector, Vector3d cameraDir)
|
||||
private static boolean isNormalizedVectorInViewFrustum(Vector3f objectVector, Vector3f cameraDir)
|
||||
{
|
||||
// the -0.1 is to offer a slight buffer, so we are
|
||||
// more likely to render LODs and thus, hopefully prevent
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.render.shader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
|
||||
/**
|
||||
* This object holds a OpenGL reference to a shader
|
||||
* and allows for reading in and compiling a shader file.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodShader
|
||||
{
|
||||
/** OpenGL shader ID */
|
||||
public final int id;
|
||||
|
||||
|
||||
|
||||
/** Creates a shader with specified type. */
|
||||
public LodShader(int type)
|
||||
{
|
||||
id = GL20.glCreateShader(type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Loads a shader from file.
|
||||
*
|
||||
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||
* @param path File path of the shader
|
||||
* @param absoluteFilePath If false the file path is relative to the resource jar folder.
|
||||
* @throws Exception if the shader fails to compile
|
||||
*/
|
||||
public static LodShader loadShader(int type, String path, boolean absoluteFilePath) throws Exception
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
// open the file
|
||||
InputStream in = absoluteFilePath ? new FileInputStream(path) : LodShader.class.getClassLoader().getResourceAsStream(path);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
// read in the file
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
stringBuilder.append(line).append("\n");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ClientProxy.LOGGER.error("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
|
||||
}
|
||||
CharSequence shaderFileSource = stringBuilder.toString();
|
||||
|
||||
return createShader(type, shaderFileSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shader with the specified type and source.
|
||||
*
|
||||
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||
* @param source Source of the shader
|
||||
* @throws Exception if the shader fails to compile
|
||||
*/
|
||||
public static LodShader createShader(int type, CharSequence source) throws Exception
|
||||
{
|
||||
LodShader shader = new LodShader(type);
|
||||
GL20.glShaderSource(shader.id, source);
|
||||
shader.compile();
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the shader and checks it's status afterwards.
|
||||
* @throws Exception if the shader fails to compile
|
||||
*/
|
||||
public void compile() throws Exception
|
||||
{
|
||||
GL20.glCompileShader(id);
|
||||
|
||||
// check if the shader compiled
|
||||
int status = GL20.glGetShaderi(id, GL20.GL_COMPILE_STATUS);
|
||||
if (status != GL20.GL_TRUE)
|
||||
throw new Exception(GL20.glGetShaderInfoLog(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.render.shader;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
|
||||
|
||||
/**
|
||||
* This object holds the reference to a OpenGL shader program
|
||||
* and contains a few methods that can be used with OpenGL shader programs.
|
||||
* The reason for many of these simple wrapper methods is as reminders of what
|
||||
* can (and needs to be) done with a shader program.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodShaderProgram
|
||||
{
|
||||
/** Stores the handle of the program. */
|
||||
public final int id;
|
||||
|
||||
/** Creates a shader program. */
|
||||
public LodShaderProgram()
|
||||
{
|
||||
id = GL20.glCreateProgram();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Calls GL20.glUseProgram(this.id) */
|
||||
public void use()
|
||||
{
|
||||
GL20.glUseProgram(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls GL20.glAttachShader(this.id, shader.id)
|
||||
*
|
||||
* @param shader Shader to get attached
|
||||
*/
|
||||
public void attachShader(LodShader shader)
|
||||
{
|
||||
GL20.glAttachShader(this.id, shader.id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Links the shader program to the current OpenGL context.
|
||||
* @throws Exception Exception if the program failed to link
|
||||
*/
|
||||
public void link() throws Exception
|
||||
{
|
||||
GL20.glLinkProgram(this.id);
|
||||
checkLinkStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the program was linked successfully.
|
||||
* @throws Exception if the program failed to link
|
||||
*/
|
||||
public void checkLinkStatus() throws Exception
|
||||
{
|
||||
int status = GL20.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
|
||||
if (status != GL20.GL_TRUE)
|
||||
throw new Exception(GL20.glGetProgramInfoLog(this.id));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the location of an attribute variable with specified name.
|
||||
* Calls GL20.glGetAttribLocation(id, name)
|
||||
*
|
||||
* @param name Attribute name
|
||||
*
|
||||
* @return Location of the attribute
|
||||
*/
|
||||
public int getAttributeLocation(CharSequence name)
|
||||
{
|
||||
return GL20.glGetAttribLocation(id, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls GL20.glEnableVertexAttribArray(location)
|
||||
*
|
||||
* @param location Location of the vertex attribute
|
||||
*/
|
||||
public void enableVertexAttribute(int location)
|
||||
{
|
||||
GL20.glEnableVertexAttribArray(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls GL20.glDisableVertexAttribArray(location)
|
||||
*
|
||||
* @param location Location of the vertex attribute
|
||||
*/
|
||||
public void disableVertexAttribute(int location)
|
||||
{
|
||||
GL20.glDisableVertexAttribArray(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertex attribute pointer.
|
||||
* Calls GL20.glVertexAttribPointer(...)
|
||||
*
|
||||
* @param location Location of the vertex attribute
|
||||
* @param size Number of values per vertex
|
||||
* @param stride Offset between consecutive generic vertex attributes in
|
||||
* bytes
|
||||
* @param offset Offset of the first component of the first generic vertex
|
||||
* attribute in bytes
|
||||
*/
|
||||
public void pointVertexAttribute(int location, int size, int stride, int offset)
|
||||
{
|
||||
GL20.glVertexAttribPointer(location, size, GL20.GL_FLOAT, false, stride, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of an uniform variable with specified name.
|
||||
* Calls GL20.glGetUniformLocation(id, name)
|
||||
*
|
||||
* @param name Uniform name
|
||||
*
|
||||
* @return -1 = error value, 0 = first value, 1 = second value, etc.
|
||||
*/
|
||||
public int getUniformLocation(CharSequence name)
|
||||
{
|
||||
return GL20.glGetUniformLocation(id, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uniform variable for specified location.
|
||||
*
|
||||
* @param location Uniform location
|
||||
* @param value Value to set
|
||||
*/
|
||||
public void setUniform(int location, int value)
|
||||
{
|
||||
GL20.glUniform1i(location, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uniform variable for specified location.
|
||||
*
|
||||
* @param location Uniform location
|
||||
* @param value Value to set
|
||||
*/
|
||||
public void setUniform(int location, Matrix4f value)
|
||||
{
|
||||
try (MemoryStack stack = MemoryStack.stackPush())
|
||||
{
|
||||
FloatBuffer buffer = stack.mallocFloat(4 * 4);
|
||||
value.store(buffer);
|
||||
GL20.glUniformMatrix4fv(location, false, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import com.seibel.lod.enums.HorizontalResolution;
|
||||
import com.seibel.lod.enums.VanillaOverdraw;
|
||||
import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.objects.RegionPos;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
@@ -349,10 +351,10 @@ public class LodUtil
|
||||
* Get a HashSet of all ChunkPos within the normal render distance
|
||||
* that should not be rendered.
|
||||
*/
|
||||
public static HashSet<ChunkPos> getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos)
|
||||
public static HashSet<ChunkPos> getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
int chunkRenderDist = mc.getRenderDistance();
|
||||
ChunkPos centerChunk = new ChunkPos(playerPos);
|
||||
ChunkPosWrapper centerChunk = new ChunkPosWrapper(blockPosWrapper);
|
||||
|
||||
int skipRadius;
|
||||
VanillaOverdraw overdraw = LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.get();
|
||||
@@ -426,12 +428,12 @@ public class LodUtil
|
||||
// if the skipRadius is being used
|
||||
if (skipRadius != 0)
|
||||
{
|
||||
for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++)
|
||||
for (int x = centerChunk.getX() - chunkRenderDist; x < centerChunk.getX() + chunkRenderDist; x++)
|
||||
{
|
||||
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
|
||||
for (int z = centerChunk.getZ() - chunkRenderDist; z < centerChunk.getZ() + chunkRenderDist; z++)
|
||||
{
|
||||
if (x <= centerChunk.x - skipRadius || x >= centerChunk.x + skipRadius
|
||||
|| z <= centerChunk.z - skipRadius || z >= centerChunk.z + skipRadius)
|
||||
if (x <= centerChunk.getX() - skipRadius || x >= centerChunk.getX() + skipRadius
|
||||
|| z <= centerChunk.getZ() - skipRadius || z >= centerChunk.getZ() + skipRadius)
|
||||
posToSkip.remove(new ChunkPos(x, z));
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
package com.seibel.lod.util;
|
||||
|
||||
import static com.seibel.lod.util.LodUtil.DETAIL_OPTIONS;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -80,7 +78,7 @@ public class ThreadMapUtil
|
||||
|| (adjDataMap.get(Thread.currentThread().getName()).get(Direction.NORTH) == null)
|
||||
|| (adjDataMap.get(Thread.currentThread().getName()).get(Direction.NORTH).length != verticalData))
|
||||
{
|
||||
adjDataMap.put(Thread.currentThread().getName(), new HashMap<Direction, long[]>());
|
||||
adjDataMap.put(Thread.currentThread().getName(), new HashMap<>());
|
||||
adjDataMap.get(Thread.currentThread().getName()).put(Direction.UP, new long[1]);
|
||||
adjDataMap.get(Thread.currentThread().getName()).put(Direction.DOWN, new long[1]);
|
||||
for (Direction direction : Box.ADJ_DIRECTIONS)
|
||||
@@ -142,9 +140,9 @@ public class ThreadMapUtil
|
||||
{
|
||||
if (!saveContainer.containsKey(Thread.currentThread().getName()) || (saveContainer.get(Thread.currentThread().getName()) == null))
|
||||
{
|
||||
byte[][] array = new byte[DETAIL_OPTIONS][];
|
||||
byte[][] array = new byte[LodUtil.DETAIL_OPTIONS][];
|
||||
int size = 1;
|
||||
for (int i = DETAIL_OPTIONS - 1; i >= 0; i--)
|
||||
for (int i = LodUtil.DETAIL_OPTIONS - 1; i >= 0; i--)
|
||||
{
|
||||
array[i] = new byte[2 + 8 * size * size * DetailDistanceUtil.getMaxVerticalData(i)];
|
||||
size = size << 1;
|
||||
@@ -188,8 +186,8 @@ public class ThreadMapUtil
|
||||
{
|
||||
if (!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null))
|
||||
{
|
||||
long[][] array = new long[DETAIL_OPTIONS][];
|
||||
for (int i = 1; i < DETAIL_OPTIONS; i++)
|
||||
long[][] array = new long[LodUtil.DETAIL_OPTIONS][];
|
||||
for (int i = 1; i < LodUtil.DETAIL_OPTIONS; i++)
|
||||
array[i] = new long[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
|
||||
verticalUpdate.put(Thread.currentThread().getName(), array);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class BlockColorWrapper
|
||||
//set of block which require tint
|
||||
public static final ConcurrentMap<Block, BlockColorWrapper> blockColorWrapperMap = new ConcurrentHashMap<>();
|
||||
public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
||||
public static final BlockPos blockPos = new BlockPos(0,0,0);
|
||||
public static final BlockPos blockPos = new BlockPos(0, 0, 0);
|
||||
public static final Random random = new Random(0);
|
||||
//public static BlockColourWrapper WATER_COLOR = getBlockColorWrapper(Blocks.WATER);
|
||||
public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
|
||||
@@ -37,33 +37,51 @@ public class BlockColorWrapper
|
||||
|
||||
|
||||
/**Constructor only require for the block instance we are wrapping**/
|
||||
public BlockColorWrapper(BlockState blockState, BlockPosWrapper blockPosWrapper)
|
||||
public BlockColorWrapper(Block block)
|
||||
{
|
||||
this.block = blockState.getBlock();
|
||||
this.block = block;
|
||||
this.color = 0;
|
||||
this.isColored = true;
|
||||
this.toTint = false;
|
||||
this.foliageTint = false;
|
||||
this.grassTint = false;
|
||||
this.waterTint = false;
|
||||
setupColorAndTint(blockState,blockPosWrapper);
|
||||
setupColorAndTint();
|
||||
/*StringBuilder s = new StringBuilder();
|
||||
s.append(block + "\n"
|
||||
+ Integer.toHexString(
|
||||
Minecraft.getInstance().getBlockColors().createDefault().getColor(
|
||||
block.defaultBlockState(),
|
||||
(World) MinecraftWrapper.INSTANCE.getWrappedServerLevel().getLevel(),
|
||||
blockPosWrapper.getBlockPos())) + "\n"
|
||||
);
|
||||
for(Property x : Minecraft.getInstance().getBlockColors().getColoringProperties(block))
|
||||
s.append(x.getName() + " " + x.getPossibleValues() + '\n');
|
||||
System.out.println(s);*/
|
||||
//System.out.println(block + " color " + Integer.toHexString(color) + " to tint " + toTint + " folliageTint " + folliageTint + " grassTint " + grassTint + " waterTint " + waterTint);
|
||||
}
|
||||
|
||||
/**
|
||||
* this return a wrapper of the block in input
|
||||
* @param blockState of the block to wrap
|
||||
* return base color of water (grey value)
|
||||
*/
|
||||
static public BlockColorWrapper getBlockColorWrapper(BlockState blockState, BlockPosWrapper blockPosWrapper)
|
||||
static public BlockColorWrapper getWaterColor()
|
||||
{
|
||||
return getBlockColorWrapper(Blocks.WATER);
|
||||
}
|
||||
/**
|
||||
* this return a wrapper of the block in input
|
||||
* @param block object of the block to wrap
|
||||
*/
|
||||
static public BlockColorWrapper getBlockColorWrapper(Block block)
|
||||
{
|
||||
//first we check if the block has already been wrapped
|
||||
if (blockColorWrapperMap.containsKey(blockState.getBlock()) && blockColorWrapperMap.get(blockState.getBlock()) != null)
|
||||
return blockColorWrapperMap.get(blockState.getBlock());
|
||||
if (blockColorWrapperMap.containsKey(block) && blockColorWrapperMap.get(block) != null)
|
||||
return blockColorWrapperMap.get(block);
|
||||
|
||||
|
||||
//if it hasn't been created yet, we create it and save it in the map
|
||||
BlockColorWrapper blockWrapper = new BlockColorWrapper(blockState, blockPosWrapper);
|
||||
blockColorWrapperMap.put(blockState.getBlock(), blockWrapper);
|
||||
BlockColorWrapper blockWrapper = new BlockColorWrapper(block);
|
||||
blockColorWrapperMap.put(block, blockWrapper);
|
||||
|
||||
//we return the newly created wrapper
|
||||
return blockWrapper;
|
||||
@@ -73,8 +91,10 @@ public class BlockColorWrapper
|
||||
* Generate the color of the given block from its texture
|
||||
* and store it for later use.
|
||||
*/
|
||||
private void setupColorAndTint(BlockState blockState, BlockPosWrapper blockPosWrapper)
|
||||
private void setupColorAndTint()
|
||||
{
|
||||
BlockState blockState = block.defaultBlockState();
|
||||
BlockPosWrapper blockPosWrapper = new BlockPosWrapper();
|
||||
MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
TextureAtlasSprite texture;
|
||||
List<BakedQuad> quads = null;
|
||||
@@ -114,7 +134,7 @@ public class BlockColorWrapper
|
||||
else
|
||||
{
|
||||
isColored = true;
|
||||
texture = mc.getModelManager().getBlockModelShaper().getTexture(block.defaultBlockState(), mc.getClientWorld(), blockPosWrapper.getBlockPos());
|
||||
texture = mc.getModelManager().getBlockModelShaper().getTexture(block.defaultBlockState(), mc.getClientLevel(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
@@ -229,7 +249,7 @@ public class BlockColorWrapper
|
||||
|
||||
public int getColor()
|
||||
{
|
||||
return color;
|
||||
return color;
|
||||
}
|
||||
|
||||
//------------//
|
||||
|
||||
@@ -1,64 +1,67 @@
|
||||
package com.seibel.lod.wrappers.Block;
|
||||
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class BlockPosWrapper {
|
||||
private final BlockPos.Mutable blockPos;
|
||||
|
||||
|
||||
//This class wraps the minecraft BlockPos.Mutable (and BlockPos) class
|
||||
public class BlockPosWrapper
|
||||
{
|
||||
private final BlockPos.Mutable blockPos;
|
||||
|
||||
|
||||
public BlockPosWrapper()
|
||||
{
|
||||
this.blockPos = new BlockPos.Mutable(0,0,0);
|
||||
}
|
||||
|
||||
public void set(int x, int y, int z)
|
||||
{
|
||||
blockPos.set(x, y, z);
|
||||
}
|
||||
|
||||
public int getX()
|
||||
{
|
||||
return blockPos.getX();
|
||||
}
|
||||
|
||||
public int getY()
|
||||
{
|
||||
return blockPos.getY();
|
||||
}
|
||||
|
||||
public int getZ()
|
||||
{
|
||||
return blockPos.getZ();
|
||||
}
|
||||
|
||||
public BlockPos.Mutable getBlockPos()
|
||||
{
|
||||
return blockPos;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o)
|
||||
{
|
||||
return blockPos.equals(o);
|
||||
}
|
||||
|
||||
@Override public int hashCode()
|
||||
{
|
||||
return Objects.hash(blockPos);
|
||||
}
|
||||
|
||||
public BlockPosWrapper()
|
||||
{
|
||||
this.blockPos = new BlockPos.Mutable(0,0,0);
|
||||
}
|
||||
|
||||
public BlockPosWrapper(int x, int y, int z)
|
||||
{
|
||||
this.blockPos = new BlockPos.Mutable(x, y, z);
|
||||
}
|
||||
|
||||
public void set(int x, int y, int z)
|
||||
{
|
||||
blockPos.set(x, y, z);
|
||||
}
|
||||
|
||||
public int getX()
|
||||
{
|
||||
return blockPos.getX();
|
||||
}
|
||||
|
||||
public int getY()
|
||||
{
|
||||
return blockPos.getY();
|
||||
}
|
||||
|
||||
public int getZ()
|
||||
{
|
||||
return blockPos.getZ();
|
||||
}
|
||||
|
||||
public int get(Direction.Axis axis)
|
||||
{
|
||||
return axis.choose(getX(), getY(), getZ());
|
||||
}
|
||||
|
||||
public BlockPos.Mutable getBlockPos()
|
||||
{
|
||||
return blockPos;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o)
|
||||
{
|
||||
return blockPos.equals(o);
|
||||
}
|
||||
|
||||
@Override public int hashCode()
|
||||
{
|
||||
return Objects.hash(blockPos);
|
||||
}
|
||||
|
||||
public BlockPosWrapper offset(int x, int y, int z)
|
||||
{
|
||||
blockPos.set(blockPos.getX() + x, blockPos.getY() + y, blockPos.getZ() + z);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class BlockShapeWrapper
|
||||
public static BlockShapeWrapper WATER_SHAPE = new BlockShapeWrapper();
|
||||
|
||||
private final Block block;
|
||||
private final boolean toAvoid;
|
||||
private boolean toAvoid;
|
||||
private boolean nonFull;
|
||||
private boolean noCollision;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.seibel.lod.wrappers.Chunk;
|
||||
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
|
||||
@@ -11,9 +13,30 @@ public class ChunkPosWrapper
|
||||
{
|
||||
private final ChunkPos chunkPos;
|
||||
|
||||
public ChunkPosWrapper(ChunkPos chunkPos)
|
||||
public ChunkPosWrapper(ChunkPos newChunkPos)
|
||||
{
|
||||
this.chunkPos = newChunkPos;
|
||||
}
|
||||
|
||||
public ChunkPosWrapper(BlockPos blockPos)
|
||||
{
|
||||
this.chunkPos = new ChunkPos(blockPos);
|
||||
}
|
||||
|
||||
|
||||
public ChunkPosWrapper(ChunkPosWrapper newChunkPos)
|
||||
{
|
||||
this.chunkPos = newChunkPos.chunkPos;
|
||||
}
|
||||
|
||||
public ChunkPosWrapper(BlockPosWrapper blockPos)
|
||||
{
|
||||
this.chunkPos = chunkPos;
|
||||
this.chunkPos = new ChunkPos(blockPos.getBlockPos());
|
||||
}
|
||||
|
||||
public ChunkPosWrapper(int chunkX, int chunkZ)
|
||||
{
|
||||
this.chunkPos = new ChunkPos(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public int getX()
|
||||
@@ -61,4 +84,9 @@ public class ChunkPosWrapper
|
||||
return Objects.hash(chunkPos);
|
||||
}
|
||||
|
||||
public BlockPosWrapper getWorldPosition()
|
||||
{
|
||||
BlockPos blockPos = chunkPos.getWorldPosition();
|
||||
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,8 @@ public class ChunkWrapper
|
||||
BlockState blockState = chunk.getBlockState(blockPos.getBlockPos());
|
||||
|
||||
//This type of block is always in water
|
||||
//This type of block could be in water
|
||||
return ((blockState.getBlock() instanceof ILiquidContainer) && !(blockState.getBlock() instanceof IWaterLoggable))
|
||||
|| (blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).isPresent() && blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).get());
|
||||
|| (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
|
||||
}
|
||||
|
||||
public int getHeightMapValue(int xRel, int zRel){
|
||||
@@ -42,7 +41,7 @@ public class ChunkWrapper
|
||||
|
||||
public BlockColorWrapper getBlockColorWrapper(BlockPosWrapper blockPos)
|
||||
{
|
||||
return BlockColorWrapper.getBlockColorWrapper(chunk.getBlockState(blockPos.getBlockPos()),blockPos);
|
||||
return BlockColorWrapper.getBlockColorWrapper(chunk.getBlockState(blockPos.getBlockPos()).getBlock());
|
||||
}
|
||||
|
||||
public BlockShapeWrapper getBlockShapeWrapper(BlockPosWrapper blockPos)
|
||||
@@ -73,9 +72,8 @@ public class ChunkWrapper
|
||||
BlockState blockState = chunk.getBlockState(blockPos.getBlockPos());
|
||||
|
||||
//This type of block is always in water
|
||||
//This type of block could be in water
|
||||
return ((blockState.getBlock() instanceof ILiquidContainer) && !(blockState.getBlock() instanceof IWaterLoggable))
|
||||
|| (blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).isPresent() && blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).get());
|
||||
|| (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
|
||||
}
|
||||
|
||||
public int getEmittedBrightness(BlockPosWrapper blockPos)
|
||||
|
||||
@@ -26,7 +26,9 @@ import com.seibel.lod.ModInfo;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import com.seibel.lod.wrappers.World.WorldWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.World.LevelWrapper;
|
||||
import net.minecraft.client.GameSettings;
|
||||
import net.minecraft.client.MainWindow;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -44,6 +46,7 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.profiler.IProfiler;
|
||||
import net.minecraft.server.integrated.IntegratedServer;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
@@ -170,6 +173,17 @@ public class MinecraftWrapper
|
||||
return mc.player;
|
||||
}
|
||||
|
||||
public BlockPosWrapper getPlayerBlockPos()
|
||||
{
|
||||
BlockPos playerPos = getPlayer().blockPosition();
|
||||
return new BlockPosWrapper(playerPos.getX(), playerPos.getY(), playerPos.getZ());
|
||||
}
|
||||
|
||||
public ChunkPosWrapper getPlayerChunkPos()
|
||||
{
|
||||
return new ChunkPosWrapper(getPlayer().xChunk, getPlayer().zChunk);
|
||||
}
|
||||
|
||||
public GameSettings getOptions()
|
||||
{
|
||||
return mc.options;
|
||||
@@ -180,17 +194,17 @@ public class MinecraftWrapper
|
||||
return mc.getModelManager();
|
||||
}
|
||||
|
||||
public ClientWorld getClientWorld()
|
||||
public ClientWorld getClientLevel()
|
||||
{
|
||||
return mc.level;
|
||||
}
|
||||
|
||||
public WorldWrapper getWrappedClientWorld()
|
||||
public LevelWrapper getWrappedClientLevel()
|
||||
{
|
||||
return WorldWrapper.getWorldWrapper(mc.level);
|
||||
return LevelWrapper.getLevelWrapper(mc.level);
|
||||
}
|
||||
|
||||
public WorldWrapper getWrappedServerWorld()
|
||||
public LevelWrapper getWrappedServerLevel()
|
||||
{
|
||||
|
||||
if (mc.level == null)
|
||||
@@ -212,7 +226,7 @@ public class MinecraftWrapper
|
||||
}
|
||||
}
|
||||
|
||||
return WorldWrapper.getWorldWrapper(returnWorld);
|
||||
return LevelWrapper.getLevelWrapper(returnWorld);
|
||||
}
|
||||
|
||||
/** Measured in chunks */
|
||||
|
||||
@@ -1,33 +1,24 @@
|
||||
package com.seibel.lod.wrappers.World;
|
||||
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.material.MaterialColor;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeColors;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
|
||||
public class BiomeColorWrapper
|
||||
{
|
||||
|
||||
public static int getGrassColor(WorldWrapper worldWrapper, BlockPosWrapper blockPosWrapper)
|
||||
public static int getGrassColor(LevelWrapper levelWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
return BiomeColors.getAverageGrassColor(worldWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
return BiomeColors.getAverageGrassColor(levelWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
public static int getWaterColor(WorldWrapper worldWrapper, BlockPosWrapper blockPosWrapper)
|
||||
public static int getWaterColor(LevelWrapper levelWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
|
||||
return BiomeColors.getAverageWaterColor(worldWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
return BiomeColors.getAverageWaterColor(levelWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
public static int getFoliageColor(WorldWrapper worldWrapper, BlockPosWrapper blockPosWrapper)
|
||||
public static int getFoliageColor(LevelWrapper levelWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
|
||||
return BiomeColors.getAverageFoliageColor(worldWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
return BiomeColors.getAverageFoliageColor(levelWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
package com.seibel.lod.wrappers.World;
|
||||
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockColorWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.material.MaterialColor;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeColors;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -48,57 +42,72 @@ public class BiomeWrapper
|
||||
public int getColorForBiome(int x, int z)
|
||||
{
|
||||
int colorInt;
|
||||
int tintValue = 0;
|
||||
|
||||
switch (biome.getBiomeCategory())
|
||||
{
|
||||
|
||||
case NETHER:
|
||||
colorInt = Blocks.NETHERRACK.defaultBlockState().materialColor.col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.NETHERRACK).getColor();
|
||||
break;
|
||||
|
||||
case THEEND:
|
||||
colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.END_STONE).getColor();
|
||||
break;
|
||||
|
||||
case BEACH:
|
||||
case DESERT:
|
||||
colorInt = Blocks.SAND.defaultBlockState().materialColor.col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.SAND).getColor();
|
||||
break;
|
||||
|
||||
case EXTREME_HILLS:
|
||||
colorInt = Blocks.STONE.defaultMaterialColor().col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.STONE).getColor();
|
||||
break;
|
||||
|
||||
case MUSHROOM:
|
||||
colorInt = MaterialColor.COLOR_LIGHT_GRAY.col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.MYCELIUM).getColor();
|
||||
break;
|
||||
|
||||
case ICY:
|
||||
colorInt = Blocks.SNOW.defaultMaterialColor().col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.SNOW).getColor();
|
||||
break;
|
||||
|
||||
case MESA:
|
||||
colorInt = Blocks.RED_SAND.defaultMaterialColor().col;
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.RED_SAND).getColor();
|
||||
break;
|
||||
|
||||
case OCEAN:
|
||||
case RIVER:
|
||||
colorInt = biome.getWaterColor();
|
||||
colorInt = BlockColorWrapper.getWaterColor().getColor();
|
||||
tintValue = biome.getWaterColor();
|
||||
break;
|
||||
|
||||
case PLAINS:
|
||||
case SAVANNA:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.GRASS_BLOCK).getColor();
|
||||
tintValue = biome.getGrassColor(x, z);
|
||||
colorInt = ColorUtil.multiplyRGBcolors(colorInt,tintValue);
|
||||
break;
|
||||
|
||||
case TAIGA:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.SPRUCE_LEAVES).getColor();
|
||||
tintValue = biome.getFoliageColor();
|
||||
colorInt = ColorUtil.multiplyRGBcolors(colorInt,tintValue);
|
||||
break;
|
||||
case JUNGLE:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.JUNGLE_LEAVES).getColor();
|
||||
tintValue = biome.getFoliageColor();
|
||||
colorInt = ColorUtil.multiplyRGBcolors(colorInt,tintValue);
|
||||
break;
|
||||
|
||||
case NONE:
|
||||
case FOREST:
|
||||
case TAIGA:
|
||||
case JUNGLE:
|
||||
case PLAINS:
|
||||
case SAVANNA:
|
||||
case SWAMP:
|
||||
default:
|
||||
Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z));
|
||||
tmp = tmp.darker();
|
||||
colorInt = LodUtil.colorToInt(tmp);
|
||||
case SWAMP:
|
||||
case FOREST:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.OAK_LEAVES).getColor();
|
||||
tintValue = biome.getFoliageColor();
|
||||
colorInt = ColorUtil.multiplyRGBcolors(colorInt,tintValue);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return colorInt;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.seibel.lod.wrappers.World;
|
||||
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.LightType;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class LevelWrapper
|
||||
{
|
||||
private static final ConcurrentMap<IWorld, LevelWrapper> worldWrapperMap = new ConcurrentHashMap<>();
|
||||
private final IWorld world;
|
||||
|
||||
public LevelWrapper(IWorld world)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
|
||||
public static LevelWrapper getLevelWrapper(IWorld world)
|
||||
{
|
||||
//first we check if the biome has already been wrapped
|
||||
if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null)
|
||||
return worldWrapperMap.get(world);
|
||||
|
||||
|
||||
//if it hasn't been created yet, we create it and save it in the map
|
||||
LevelWrapper levelWrapper = new LevelWrapper(world);
|
||||
worldWrapperMap.put(world, levelWrapper);
|
||||
|
||||
//we return the newly created wrapper
|
||||
return levelWrapper;
|
||||
}
|
||||
|
||||
public static void clearMap()
|
||||
{
|
||||
worldWrapperMap.clear();
|
||||
}
|
||||
|
||||
public DimensionTypeWrapper getDimensionType()
|
||||
{
|
||||
return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
|
||||
}
|
||||
|
||||
public int getBlockLight(BlockPosWrapper blockPos)
|
||||
{
|
||||
return world.getBrightness(LightType.BLOCK, blockPos.getBlockPos());
|
||||
}
|
||||
|
||||
public int getSkyLight(BlockPosWrapper blockPos)
|
||||
{
|
||||
return world.getBrightness(LightType.SKY, blockPos.getBlockPos());
|
||||
}
|
||||
|
||||
public BiomeWrapper getBiome(BlockPosWrapper blockPos)
|
||||
{
|
||||
return BiomeWrapper.getBiomeWrapper(world.getBiome(blockPos.getBlockPos()));
|
||||
}
|
||||
|
||||
public IWorld getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
public boolean hasCeiling()
|
||||
{
|
||||
return world.dimensionType().hasCeiling();
|
||||
}
|
||||
|
||||
public boolean hasSkyLight()
|
||||
{
|
||||
return world.dimensionType().hasSkyLight();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return world == null;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,9 @@ displayURL="https://www.curseforge.com/minecraft/mc-mods/lod-level-of-detail" #o
|
||||
#// A file name (in the root of the mod JAR) containing a logo for display
|
||||
logoFile="logo.png" #optional
|
||||
|
||||
#// A file name (in the root of the mod JAR) containing a icon for display by catalogue
|
||||
catalogueImageIcon="icon.png"
|
||||
|
||||
#// A text field displayed in the mod UI
|
||||
credits="TechnoVision, Vike, and Darkhax for their modding tutorials." #optional
|
||||
|
||||
@@ -45,4 +48,4 @@ credits="TechnoVision, Vike, and Darkhax for their modding tutorials." #optional
|
||||
authors="James Seibel, Leonardo Amato, and Cola" #optional
|
||||
|
||||
#// The description text for the mod (multi line!) (#mandatory)
|
||||
description='''This mod generates and renders simplified terrain beyond the normal view distance, at a low performance cost.'''
|
||||
description='''This mod generates and renders simplified terrain beyond the normal view distance, at a low performance cost.'''
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,26 @@
|
||||
#version 150 core
|
||||
|
||||
in vec4 vertexColor;
|
||||
//in vec2 textureCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
//uniform sampler2D texImage;
|
||||
|
||||
|
||||
/**
|
||||
* Fragment Shader
|
||||
*
|
||||
* author: James Seibel
|
||||
* version: 11-8-2021
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
// TODO: add a white texture to support Optifine shaders
|
||||
//vec4 textureColor = texture(texImage, textureCoord);
|
||||
//fragColor = vertexColor * textureColor;
|
||||
|
||||
|
||||
// very simple fragment shader, just return the vertix's color
|
||||
fragColor = vertexColor;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#version 150 core
|
||||
|
||||
in vec3 vPosition;
|
||||
in vec4 color;
|
||||
|
||||
out vec4 vertexColor;
|
||||
//out vec2 textureCoord;
|
||||
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
|
||||
/**
|
||||
* Vertex Shader
|
||||
*
|
||||
* author: James Seibel
|
||||
* version: 11-8-2021
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
// TODO: add a simple white texture to support Optifine shaders
|
||||
//textureCoord = textureCoord;
|
||||
|
||||
vertexColor = color;
|
||||
|
||||
// the vPosition needs to be converted to a vec4 so it can be multiplied
|
||||
// by the 4x4 matrices
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user