Compare commits

..

28 Commits

Author SHA1 Message Date
James Seibel 4ad081e0c6 Add a advanced graphics option to use a extended near clip plain
This prevents some overdraw issues but causes LODs in the ocean to render incorrectly.
2021-10-25 22:20:00 -05:00
James Seibel 936a3a7ece Fix #84 (misaligned LODs in third person) 2021-10-25 21:56:22 -05:00
Leonardo 98f36936d0 smallFix 2021-10-25 22:57:37 +02:00
Leonardo f6f012c42c Added some other classes/methods to the wrappers 2021-10-25 22:51:01 +02:00
Leonardo a3e6c09268 Added more methods to the wrapper 2021-10-25 22:31:43 +02:00
Leonardo 10cb46c9f9 Added biomeWrapper 2021-10-25 21:30:44 +02:00
Leonardo 95aa9cb9ab Merge remote-tracking branch 'origin/1.16.5' into 1.16.5 2021-10-25 20:20:47 +02:00
Leonardo 638a0ddae1 BlockPosWrapper and BlockWrapper almost completed 2021-10-25 20:20:40 +02:00
James Seibel d321833335 Merge branch '1.16.5' of gitlab.com:jeseibel/minecraft-lod-mod into 1.16.5 2021-10-25 07:21:26 -05:00
James Seibel b8cba0dc4c increase the near clip plane to 1/5 MC's vanilla render distance 2021-10-25 07:21:17 -05:00
cola98765 bd8ccb4a05 reverted las change, fixed vanillaRenderedChunksChanged at hight altitudes 2021-10-25 13:20:13 +02:00
cola98765 895895da04 update buffers only when lightmap changes. 2021-10-25 12:43:59 +02:00
Leonardo 09d5df2856 Added the main wrapper classes (empty) 2021-10-25 11:14:17 +02:00
James Seibel 668f225528 Fix the blindness potion effect 2021-10-24 23:02:30 -05:00
James Seibel 1cd71a6b50 Re-arange Vanilla Overdraw config options 2021-10-24 22:18:09 -05:00
James Seibel f041f79ae3 Close #78 (Add a config to disable vanilla MC's fog)
And change the config to use FAR fog and disable MC's fog by default.
2021-10-24 22:17:57 -05:00
James Seibel ef3ac96b2c Merge branch '1.16.5' of gitlab.com:jeseibel/minecraft-lod-mod into 1.16.5 2021-10-24 21:30:35 -05:00
James Seibel 59f527e6de Update 1.5 release notes.txt 2021-10-24 15:19:59 -05:00
James Seibel 16a082b17f rename "Disable Drawing" to "Enable Rendering" in the config
The config name was incorrect.
2021-10-24 15:19:54 -05:00
jas35484 a24d28b0e2 Merge branch '1.16.5' of gitlab.com:jeseibel/minecraft-lod-mod into 1.16.5 2021-10-24 14:57:56 -05:00
jas35484 910f11f688 Fix #63 (OpenGL errors)
NVFogDistance doesn't work on low end GPUs which causes the OpenGL error I was seeing with Optifine
2021-10-24 14:57:53 -05:00
cola98765 e00de99e31 Found place where addData was used for adding whole vertical array. We have addVerticalData for that. 2021-10-24 12:11:43 +02:00
cola98765 f80af39e0e halving every array related to worldHeight, as you can't get worldHeight lods, as half of that needs to be a gaps 2021-10-24 11:57:08 +02:00
cola98765 5bba3cb3eb minor cleanup 2021-10-24 11:35:45 +02:00
cola98765 d4261d4ccf a little improvement to 'pow' changes 2021-10-24 11:01:02 +02:00
cola98765 8b854e3abd removed debug message 2021-10-24 10:33:02 +02:00
cola98765 4064155567 changed Math.pow usages with simpler (and possibly faster) x*x and 1 << x. reduced repetitions 2021-10-24 10:28:35 +02:00
cola98765 6243201f2d removed couple Math.floorDiv and Mod as for positive inputs they are slower and give the same result as standard operands 2021-10-24 10:08:12 +02:00
25 changed files with 868 additions and 169 deletions
Binary file not shown.
@@ -181,8 +181,7 @@ public class LodBufferBuilder
generatingBuffers = true;
Thread thread = new Thread(() ->
generateLodBuffersThread(renderer, lodDim, playerBlockPos, fullRegen));
Thread thread = new Thread(() -> generateLodBuffersThread(renderer, lodDim, playerBlockPos, fullRegen));
mainGenThread.execute(thread);
}
@@ -243,8 +242,8 @@ public class LodBufferBuilder
if (lodDim.doesRegionNeedBufferRegen(xRegion, zRegion) || fullRegen)
{
RegionPos regionPos = new RegionPos(
xRegion + lodDim.getCenterRegionPosX() - Math.floorDiv(lodDim.getWidth(), 2),
zRegion + lodDim.getCenterRegionPosZ() - Math.floorDiv(lodDim.getWidth(), 2));
xRegion + lodDim.getCenterRegionPosX() - lodDim.getWidth() / 2,
zRegion + lodDim.getCenterRegionPosZ() - lodDim.getWidth() / 2);
// local position in the vbo and bufferBuilder arrays
BufferBuilder[] currentBuffers = buildableBuffers[xRegion][zRegion];
@@ -311,7 +310,7 @@ public class LodBufferBuilder
for (int index = 0; index < posToRender.getNumberOfPos(); index++)
{
bufferIndex = Math.floorMod(index, currentBuffers.length);
bufferIndex = index % currentBuffers.length;
detailLevel = posToRender.getNthDetailLevel(index);
posX = posToRender.getNthPosX(index);
posZ = posToRender.getNthPosZ(index);
@@ -34,6 +34,7 @@ import com.seibel.lod.enums.VerticalQuality;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
@@ -61,6 +62,7 @@ import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.data.BlockModelProvider;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
@@ -98,7 +100,6 @@ public class LodBuilder
public static final ConcurrentMap<Block, Integer> colorMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Integer> tintColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Boolean> toTint = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, VoxelShape> shapeMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Boolean> notFullBlock = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Boolean> smallBlock = new ConcurrentHashMap<>();
@@ -216,13 +217,12 @@ public class LodBuilder
return;
// determine how many LODs to generate horizontally
HorizontalResolution detail;
byte minDetailLevel = region.getMinDetailLevel();
detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
HorizontalResolution detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
// determine how many LODs to generate vertically
VerticalQuality verticalQuality = LodConfig.CLIENT.graphics.qualityOption.verticalQuality.get();
//VerticalQuality verticalQuality = LodConfig.CLIENT.graphics.qualityOption.verticalQuality.get();
byte detailLevel = detail.detailLevel;
@@ -236,18 +236,18 @@ public class LodBuilder
endX = detail.endX[i];
endZ = detail.endZ[i];
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
long[] data;
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight, DetailDistanceUtil.getMaxVerticalData(detailLevel));
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.length != 0)
lodDim.addVerticalData(detailLevel, posX, posZ, data,false);
{
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
lodDim.addVerticalData(detailLevel, posX, posZ, data, false);
}
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
}
@@ -260,7 +260,7 @@ public class LodBuilder
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail.detailLevel);
int verticalData = DataPointUtil.worldHeight;
int verticalData = DataPointUtil.worldHeight / 2 + 1;
ChunkPos chunkPos = chunk.getPos();
int height;
@@ -284,8 +284,8 @@ public class LodBuilder
for (index = 0; index < size * size; index++)
{
xRel = Math.floorMod(index, size) + startX;
zRel = Math.floorDiv(index, size) + startZ;
xRel = startX + index % size;
zRel = startZ + index / size;
xAbs = chunkPos.getMinBlockX() + xRel;
zAbs = chunkPos.getMinBlockZ() + zRel;
@@ -551,8 +551,6 @@ public class LodBuilder
if (colorMap.containsKey(block) && toTint.containsKey(block))
return colorMap.get(block);
World world = mc.getClientWorld();
TextureAtlasSprite texture;
List<BakedQuad> quads = null;
@@ -51,8 +51,9 @@ import net.minecraftforge.fml.config.ModConfig;
/**
* This handles any configuration the user has access to.
* @author Leonardo Amato
* @author James Seibel
* @version 10-23-2021
* @version 10-25-2021
*/
@Mod.EventBusSubscriber
public class LodConfig
@@ -188,6 +189,8 @@ public class LodConfig
public final ForgeConfigSpec.EnumValue<FogDrawOverride> fogDrawOverride;
public final ForgeConfigSpec.BooleanValue disableVanillaFog;
FogQualityOption(ForgeConfigSpec.Builder builder)
{
@@ -198,7 +201,7 @@ public class LodConfig
+ " At what distance should Fog be drawn on the fake chunks? \n"
+ " If the fog cuts off abruptly or you are using Optifine's \"fast\" fog option \n"
+ " set this to " + FogDistance.NEAR + " or " + FogDistance.FAR + ". \n")
.defineEnum("Fog Distance", FogDistance.NEAR_AND_FAR);
.defineEnum("Fog Distance", FogDistance.FAR);
fogDrawOverride = builder
.comment("\n\n"
@@ -208,6 +211,16 @@ public class LodConfig
+ " " + FogDrawOverride.FAST + ": Always draw fast fog on the LODs \n"
+ " " + FogDrawOverride.FANCY + ": Always draw fancy fog on the LODs (if your graphics card supports it) \n")
.defineEnum("Fog Draw Override", FogDrawOverride.FANCY);
disableVanillaFog = builder
.comment("\n\n"
+ " If true disable vanilla Minecraft's fog. \n\n"
+ ""
+ " Unlike Optifine or Sodium's fog disabling option this won't change \n"
+ " performance (we don't actually disable the fog, we just tell it to render a infinite distance away). \n"
+ " May or may not play nice with other mods edit fog. \n")
.define("Disable Vanilla Fog", true);
builder.pop();
}
}
@@ -225,6 +238,8 @@ public class LodConfig
public final ForgeConfigSpec.EnumValue<GpuUploadMethod> gpuUploadMethod;
public final ForgeConfigSpec.BooleanValue useExtendedNearClipPlane;
AdvancedGraphicsOption(ForgeConfigSpec.Builder builder)
{
@@ -269,12 +284,12 @@ public class LodConfig
+ " How often should LODs be drawn on top of regular chunks? \n"
+ " HALF and ALWAYS will prevent holes in the world, but may look odd for transparent blocks or in caves. \n\n"
+ " " + VanillaOverdraw.NEVER + ": LODs won't render on top of vanilla chunks. \n"
+ " " + VanillaOverdraw.BORDER + ": LODs will render only on the border of vanilla chunks preventing only some holes in the world. \n"
+ " " + VanillaOverdraw.DYNAMIC + ": LODs will render on top of distant vanilla chunks to hide delayed loading. \n"
+ " " + " More effective on higher render distances. \n"
+ " " + " For vanilla render distances less than or equal to " + LodUtil.MINIMUM_RENDER_DISTANCE_FOR_PARTIAL_OVERDRAW + " \n"
+ " " + " " + VanillaOverdraw.NEVER + " or " + VanillaOverdraw.ALWAYS + " may be used depending on the dimension. \n"
+ " " + VanillaOverdraw.ALWAYS + ": LODs will render on all vanilla chunks preventing holes in the world. \n"
+ " " + VanillaOverdraw.BORDER + ": LODs will render only on the border of vanilla chunks preventing only some holes in the world. \n")
+ " " + VanillaOverdraw.ALWAYS + ": LODs will render on all vanilla chunks preventing holes in the world. \n")
.defineEnum("Vanilla Overdraw", VanillaOverdraw.DYNAMIC);
gpuUploadMethod = builder
@@ -286,6 +301,14 @@ public class LodConfig
+ " " + GpuUploadMethod.BUFFER_MAPPING + ": Slow rendering but won't stutter when uploading. Possibly better than " + GpuUploadMethod.SUB_DATA + " if using a integrated GPU. \n")
.defineEnum("GPU Upload Method", GpuUploadMethod.BUFFER_STORAGE);
// This is a temporary fix (like vanilla overdraw)
// hopefully we can remove both once we get individual chunk rendering figured out
useExtendedNearClipPlane = builder
.comment("\n\n"
+ " Will prevent some overdraw issues, but may cause nearby fake chunks to render incorrectly \n"
+ " especially when in/near an ocean. \n")
.define("Use Extended Near Clip Plane", false);
builder.pop();
}
@@ -491,7 +514,7 @@ public class LodConfig
+ " If true, the mod is enabled and fake chunks will be drawn. \n"
+ " If false, the mod will still generate fake chunks, \n"
+ " but they won't be rendered. \n")
.define("Disable Drawing", true);
.define("Enable Rendering", true);
debugMode = builder
.comment("\n\n"
@@ -437,6 +437,7 @@ public class LodDimension
}
/**
* Use addVerticalData when possible.
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
* coordinate it will be overwritten.
@@ -866,7 +867,7 @@ public class LodDimension
public void setRegionWidth(int newWidth)
{
width = newWidth;
halfWidth = Math.floorDiv(width, 2);
halfWidth = width/ 2;
regions = new LodRegion[width][width];
isRegionDirty = new boolean[width][width];
@@ -36,7 +36,7 @@ public class NearFarFogSettings
/**
* If true that means Minecraft is
* rendering fog alongside us
* rendering fog
*/
public boolean vanillaIsRenderingFog = true;
@@ -56,7 +56,6 @@ public class VerticalLevelContainer implements LevelContainer
@Override
public void clear(int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
@@ -68,7 +67,6 @@ public class VerticalLevelContainer implements LevelContainer
@Override
public boolean addData(long data, int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = data;
@@ -78,7 +76,6 @@ public class VerticalLevelContainer implements LevelContainer
@Override
public boolean addVerticalData(long[] data, int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
@@ -134,7 +131,7 @@ public class VerticalLevelContainer implements LevelContainer
index++;
maxVerticalData = inputData[index];
index++;
size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int x = size * size * maxVerticalData;
this.dataContainer = new long[x];
for (int i = 0; i < x; i++)
@@ -177,13 +174,7 @@ public class VerticalLevelContainer implements LevelContainer
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData());
for (int verticalIndex = 0; (verticalIndex < data.length) && (verticalIndex < maxVerticalData); verticalIndex++)
{
addData(data[verticalIndex],
posX,
posZ,
verticalIndex);
}
addVerticalData(data, posX, posZ);
}
@Override
@@ -217,7 +208,7 @@ public class VerticalLevelContainer implements LevelContainer
{
/*
StringBuilder stringBuilder = new StringBuilder();
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
stringBuilder.append(detailLevel);
stringBuilder.append(DATA_DELIMITER);
for (int x = 0; x < size; x++)
@@ -173,9 +173,11 @@ public class ClientProxy
// LodConfig.CLIENT.worldGenerator.lodQualityMode.set(VerticalQuality.VOXEL);
// LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.set(FogDistance.FAR);
// LodConfig.CLIENT.graphics.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY);
// LodConfig.CLIENT.graphics.fogQualityOption.fogDrawOverride.set(FogDrawOverride.FANCY);
// LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.set(true);
// LodConfig.CLIENT.graphics.shadingMode.set(ShadingMode.DARKEN_SIDES);
// LodConfig.CLIENT.graphics.vanillaOverdraw.set(VanillaOverdraw.HALF);
// LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.set(VanillaOverdraw.DYNAMIC);
// LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.set(GpuUploadMethod.BUFFER_STORAGE);
@@ -21,7 +21,6 @@ package com.seibel.lod.render;
import java.util.HashSet;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.NVFogDistance;
@@ -49,10 +48,10 @@ import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.potion.Effects;
import net.minecraft.profiler.IProfiler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
@@ -65,7 +64,7 @@ import net.minecraft.util.math.vector.Vector3d;
* This is where LODs are draw to the world.
*
* @author James Seibel
* @version 10-23-2021
* @version 10-25-2021
*/
public class LodRenderer
{
@@ -73,7 +72,7 @@ public class LodRenderer
* this is the light used when rendering the LODs,
* it should be something different from what is used by Minecraft
*/
private static final int LOD_GL_LIGHT_NUMBER = GL11.GL_LIGHT2;
private static final int LOD_GL_LIGHT_NUMBER = GL15.GL_LIGHT2;
/**
* If true the LODs colors will be replaced with
@@ -106,6 +105,7 @@ public class LodRenderer
private int[] previousPos = new int[] { 0, 0, 0 };
public NativeImage lightMap = null;
public NativeImage lastLightMap = null;
// these variables are used to determine if the buffers should be rebuilt
private float prevSkyBrightness = 0;
@@ -132,6 +132,7 @@ public class LodRenderer
*/
public boolean[][] vanillaRenderedChunks;
public boolean vanillaRenderedChunksChanged;
public boolean vanillaRenderedChunksEmptySkip = false;
public int vanillaBlockRenderedDistance;
@@ -161,6 +162,10 @@ public class LodRenderer
@SuppressWarnings("deprecation")
public void drawLODs(LodDimension lodDim, MatrixStack mcMatrixStack, float partialTicks, IProfiler newProfiler)
{
//=================================//
// determine if LODs should render //
//=================================//
if (lodDim == null)
{
// if there aren't any loaded LodChunks
@@ -168,6 +173,17 @@ public class LodRenderer
return;
}
if (mc.getPlayer().getActiveEffectsMap().get(Effects.BLINDNESS) != null)
{
// if the player is blind don't render LODs,
// and don't change minecraft's fog
// which blindness relies on.
return;
}
//===============//
// initial setup //
@@ -218,27 +234,27 @@ public class LodRenderer
// set the required open GL settings
if (LodConfig.CLIENT.advancedModOptions.debugging.debugMode.get() == DebugMode.SHOW_DETAIL_WIREFRAME)
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_LINE);
else
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GL11.glEnable(GL11.GL_DEPTH_TEST);
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
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glEnable(GL11.GL_BLEND);
GL15.glBlendFunc(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA);
GL15.glEnable(GL15.GL_BLEND);
// disable the lights Minecraft uses
GL11.glDisable(GL11.GL_LIGHT0);
GL11.glDisable(GL11.GL_LIGHT1);
GL15.glDisable(GL15.GL_LIGHT0);
GL15.glDisable(GL15.GL_LIGHT1);
// get the default projection matrix, so we can
// reset it after drawing the LODs
float[] mcProjMatrixRaw = new float[16];
GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
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)
@@ -252,7 +268,8 @@ public class LodRenderer
else
farPlaneBlockDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
setupProjectionMatrix(mcProjectionMatrix, partialTicks);
setupProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, partialTicks);
// commented out until we can add shaders to handle lighting
//setupLighting(lodDim, partialTicks);
@@ -260,11 +277,10 @@ public class LodRenderer
// determine the current fog settings, so they can be
// reset after drawing the LODs
float defaultFogStartDist = GL11.glGetFloat(GL11.GL_FOG_START);
float defaultFogEndDist = GL11.glGetFloat(GL11.GL_FOG_END);
int defaultFogMode = GL11.glGetInteger(GL11.GL_FOG_MODE);
int defaultFogDistance = GL11.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV);
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;
//===========//
// rendering //
@@ -323,13 +339,13 @@ public class LodRenderer
profiler.popPush("LOD cleanup");
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(LOD_GL_LIGHT_NUMBER);
GL11.glDisable(GL11.GL_BLEND);
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
GL11.glEnable(GL11.GL_LIGHT0);
GL11.glEnable(GL11.GL_LIGHT1);
GL15.glEnable(GL15.GL_LIGHT0);
GL15.glEnable(GL15.GL_LIGHT1);
RenderSystem.disableLighting();
// reset the fog settings so the normal chunks
@@ -342,7 +358,7 @@ public class LodRenderer
// clear the depth buffer so anything drawn is drawn
// over the LODs
GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
GL15.glClear(GL15.GL_DEPTH_BUFFER_BIT);
// end of internal LOD profiling
@@ -360,7 +376,7 @@ public class LodRenderer
// 0L is the starting pointer
LodUtil.LOD_VERTEX_FORMAT.setupBufferState(0L);
vbo.draw(modelViewMatrix, GL11.GL_QUADS);
vbo.draw(modelViewMatrix, GL15.GL_QUADS);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
LodUtil.LOD_VERTEX_FORMAT.clearBufferState();
@@ -377,7 +393,7 @@ public class LodRenderer
// 0L is the starting pointer
LodUtil.LOD_VERTEX_FORMAT.setupBufferState(0L);
vbo.draw(modelViewMatrix, GL11.GL_QUADS);
vbo.draw(modelViewMatrix, GL15.GL_QUADS);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
LodUtil.LOD_VERTEX_FORMAT.clearBufferState();
@@ -395,8 +411,7 @@ public class LodRenderer
{
if (fogQuality == FogQuality.OFF)
{
FogRenderer.setupNoFog();
RenderSystem.disableFog();
GL15.glDisable(GL15.GL_FOG);
return;
}
@@ -459,15 +474,18 @@ public class LodRenderer
}
}
GL11.glEnable(GL11.GL_FOG);
GL15.glEnable(GL15.GL_FOG);
RenderSystem.enableFog();
RenderSystem.setupNvFogDistance();
RenderSystem.fogMode(GlStateManager.FogMode.LINEAR);
GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, glFogDistanceMode);
if (GlProxy.getInstance().fancyFogAvailable)
GL15.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, glFogDistanceMode);
}
/**
* Revert any changes that were made to the fog.
/**
* Revert any changes that were made to the fog
* and sets up the fog for Minecraft.
*/
@SuppressWarnings("deprecation")
private void cleanupFog(NearFarFogSettings fogSettings,
@@ -477,15 +495,27 @@ public class LodRenderer
RenderSystem.fogStart(defaultFogStartDist);
RenderSystem.fogEnd(defaultFogEndDist);
RenderSystem.fogMode(defaultFogMode);
GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, defaultFogDistance);
// disable fog if Minecraft wasn't rendering fog,
// but we were
if (!fogSettings.vanillaIsRenderingFog &&
(fogSettings.near.quality != FogQuality.OFF ||
fogSettings.far.quality != FogQuality.OFF))
// this setting is only valid if the GPU supports fancy fog
if (GlProxy.getInstance().fancyFogAvailable)
GL15.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, defaultFogDistance);
// disable fog if Minecraft wasn't rendering fog
// or we want it disabled
if (!fogSettings.vanillaIsRenderingFog
|| LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.get())
{
GL11.glDisable(GL11.GL_FOG);
// Make fog render a infinite distance away.
// This doesn't technically disable Minecraft's fog
// so performance will probably be the same regardless, unlike
// Optifine's no fog setting.
// 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);
}
}
@@ -511,12 +541,12 @@ public class LodRenderer
// (AxisAlignedBoundingBoxes (LODs) use doubles and thus have a higher
// accuracy vs the model view matrix, which only uses floats)
BlockPos bufferPos = vbosCenter.getWorldPosition();
Vector3d eyePos = mc.getPlayer().getEyePosition(partialTicks);
double xDiff = eyePos.x - bufferPos.getX();
double zDiff = eyePos.z - bufferPos.getZ();
double xDiff = projectedView.x - bufferPos.getX();
double zDiff = projectedView.z - bufferPos.getZ();
mcMatrixStack.translate(-xDiff, -projectedView.y, -zDiff);
// get the modified model view matrix
Matrix4f lodModelViewMatrix = mcMatrixStack.last().pose();
// remove the lod ModelViewMatrix
@@ -524,44 +554,21 @@ public class LodRenderer
return lodModelViewMatrix;
}
/**
* James added this to test if Vivecraft is not using
* the MC FOV setting or if the problem is deeper
*/
public enum FovTest
{
LOD_USE_FOV(true, false),
MC_USE_FOV(false, true),
NEITHER(false, false),
BOTH(true, true);
final boolean lodProjUseFov;
final boolean defaultMcProjUseFov;
FovTest(boolean newLodProjUseFov, boolean newDefaultMcProjUseFov)
{
lodProjUseFov = newLodProjUseFov;
defaultMcProjUseFov = newDefaultMcProjUseFov;
}
}
/**
* create a new projection matrix and send it over to the GPU
* @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 partialTicks)
private void setupProjectionMatrix(Matrix4f currentProjectionMatrix, float vanillaBlockRenderedDistance, float partialTicks)
{
//Minimum radious of view in 2 render distance
int minDistance = 1;
// create the new projection matrix
Matrix4f lodPoj =
Matrix4f.perspective(
getFov(partialTicks, true),
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
minDistance,
LodConfig.CLIENT.graphics.advancedGraphicsOption.useExtendedNearClipPlane.get() ? vanillaBlockRenderedDistance / 5 : 1,
farPlaneBlockDistance * LodUtil.CHUNK_WIDTH / 2);
// get Minecraft's un-edited projection matrix
@@ -625,8 +632,8 @@ public class LodRenderer
ByteBuffer temp = ByteBuffer.allocateDirect(16);
temp.order(ByteOrder.nativeOrder());
GL11.glLightfv(LOD_GL_LIGHT_NUMBER, GL11.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip());
GL11.glEnable(LOD_GL_LIGHT_NUMBER); // Enable the above lighting
GL15.glLightfv(LOD_GL_LIGHT_NUMBER, GL15.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip());
GL15.glEnable(LOD_GL_LIGHT_NUMBER); // Enable the above lighting
RenderSystem.enableLighting();
}*/
@@ -669,9 +676,7 @@ public class LodRenderer
vbosCenter = result.drawableCenterChunkPos;
}
/**
* Calls the BufferBuilder's destroyBuffers method.
*/
/** Calls the BufferBuilder's destroyBuffers method. */
public void destroyBuffers()
{
lodBufferBuilder.destroyBuffers();
@@ -684,9 +689,7 @@ public class LodRenderer
}
/**
* Return what fog settings should be used when rendering.
*/
/** Return what fog settings should be used when rendering. */
private NearFarFogSettings determineFogSettings()
{
NearFarFogSettings fogSettings = new NearFarFogSettings();
@@ -871,6 +874,11 @@ public class LodRenderer
prevSkyBrightness = skyBrightness;
}
/*if (lightMap != lastLightMap)
{
fullRegen = true;
lastLightMap = lightMap;
}*/
//================//
// partial regens //
@@ -884,7 +892,6 @@ public class LodRenderer
{
partialRegen = true;
vanillaRenderedChunksChanged = false;
}
prevVanillaChunkTime = newTime;
}
@@ -913,6 +920,8 @@ public class LodRenderer
int zIndex;
for (ChunkPos pos : chunkPosToSkip)
{
vanillaRenderedChunksEmptySkip = false;
xIndex = (pos.x - mc.getPlayer().xChunk) + (chunkRenderDistance + 1);
zIndex = (pos.z - mc.getPlayer().zChunk) + (chunkRenderDistance + 1);
@@ -933,10 +942,11 @@ public class LodRenderer
// if the player is high enough, draw all LODs
if (chunkPosToSkip.isEmpty() && mc.getPlayer().position().y > 256)
if (chunkPosToSkip.isEmpty() && mc.getPlayer().position().y > 256 && !vanillaRenderedChunksEmptySkip)
{
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
vanillaRenderedChunksChanged = true;
vanillaRenderedChunksEmptySkip = true;
}
}
@@ -282,7 +282,7 @@ public class DataPointUtil
int size = dataToMerge.length / inputVerticalData;
// We initialize the arrays that are going to be used
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((worldHeight + 1) * 2);
short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((worldHeight / 2 + 1) * 2);
long[] dataPoint = ThreadMapUtil.getVerticalDataArray(DetailDistanceUtil.getMaxVerticalData(0));
@@ -97,12 +97,13 @@ public class DetailDistanceUtil
return (byte) minDetail;
int distanceUnit = LodConfig.CLIENT.graphics.qualityOption.horizontalScale.get().distanceUnit;
if (LodConfig.CLIENT.graphics.qualityOption.horizontalQuality.get() == HorizontalQuality.LOWEST)
detail = (byte) Math.floorDiv(distance, distanceUnit);
detail = (byte) distance / distanceUnit;
else
{
double base = LodConfig.CLIENT.graphics.qualityOption.horizontalQuality.get().quadraticBase;
double logBase = Math.log(base);
detail = (byte) (Math.log(Math.floorDiv(distance, distanceUnit)) / logBase);
//noinspection IntegerDivisionInFloatingPointContext
detail = (byte) (Math.log(distance / distanceUnit) / logBase);
}
return (byte) LodUtil.clamp(minDetail, detail, maxDetail - 1);
}
@@ -119,14 +120,11 @@ public class DetailDistanceUtil
public static byte getTreeCutDetailFromDistance(int distance)
{
return baseInverseFunction((int) (distance * treeCutMultiplier), minGenDetail, true);
}
public static byte getTreeGenDetailFromDistance(int distance)
{
return baseInverseFunction((int) (distance * treeGenMultiplier), minGenDetail, true);
}
@@ -156,30 +154,20 @@ public class DetailDistanceUtil
public static HorizontalResolution getLodGenDetail(int detail)
{
if (detail < minGenDetail)
{
return lodGenDetails[minGenDetail];
}
else
{
return lodGenDetails[detail];
}
}
public static byte getCutLodDetail(int detail)
{
if (detail < minGenDetail)
{
return lodGenDetails[minGenDetail].detailLevel;
}
else if (detail == maxDetail)
{
return LodUtil.REGION_DETAIL_LEVEL;
}
else
{
return lodGenDetails[detail].detailLevel;
}
}
public static int getMaxVerticalData(int detail)
@@ -149,6 +149,10 @@ public class LevelPosUtil
return convert(detailLevel, pos, LodUtil.CHUNK_DETAIL_LEVEL);
}
public static int myPow2(int x)
{
return x*x;
}
public static int maxDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
{
@@ -156,13 +160,15 @@ public class LevelPosUtil
int startPosX = posX * width;
int startPosZ = posZ * width;
int endPosX = startPosX + width;
int endPosZ = startPosZ + width;
int endPosX = myPow2(playerPosX - startPosX - width);
int endPosZ = myPow2(playerPosZ - startPosZ - width);
startPosX = myPow2(playerPosX - startPosX);
startPosZ = myPow2(playerPosZ - startPosZ);
int maxDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
int maxDistance = (int) Math.sqrt(startPosX + startPosZ);
maxDistance = Math.max(maxDistance, (int) Math.sqrt(startPosX + endPosZ));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(endPosX + startPosZ));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(endPosX + endPosZ));
return maxDistance;
}
@@ -205,10 +211,15 @@ public class LevelPosUtil
}
else
{
int minDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
startPosX = myPow2(playerPosX - startPosX);
startPosZ = myPow2(playerPosZ - startPosZ);
endPosX = myPow2(playerPosX - endPosX);
endPosZ = myPow2(playerPosZ - endPosZ);
int minDistance = (int) Math.sqrt(startPosX + startPosZ);
minDistance = Math.min(minDistance, (int) Math.sqrt(startPosX + endPosZ));
minDistance = Math.min(minDistance, (int) Math.sqrt(endPosX + startPosZ));
minDistance = Math.min(minDistance, (int) Math.sqrt(endPosX + endPosZ));
return minDistance;
}
}
+6 -19
View File
@@ -201,8 +201,8 @@ public class LodUtil
/** Convert a 2D absolute position into a quad tree relative position. */
public static RegionPos convertGenericPosToRegionPos(int x, int z, int detailLevel)
{
int relativePosX = Math.floorDiv(x, (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel));
int relativePosZ = Math.floorDiv(z, (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel));
int relativePosX = Math.floorDiv(x, 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel));
int relativePosZ = Math.floorDiv(z, 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel));
return new RegionPos(relativePosX, relativePosZ);
}
@@ -210,7 +210,7 @@ public class LodUtil
/** Convert a 2D absolute position into a quad tree relative position. */
public static int convertLevelPos(int pos, int currentDetailLevel, int targetDetailLevel)
{
return Math.floorDiv(pos, (int) Math.pow(2, targetDetailLevel - currentDetailLevel));
return pos / (1 << (targetDetailLevel - currentDetailLevel));
}
/**
@@ -224,9 +224,7 @@ public class LodUtil
for (ChunkSection section : blockStorage)
{
if (section != null && !section.isEmpty())
{
return true;
}
}
return false;
@@ -492,20 +490,9 @@ public class LodUtil
{
tempX = x + Box.DIRECTION_NORMAL_MAP.get(direction).getX();
tempZ = z + Box.DIRECTION_NORMAL_MAP.get(direction).getZ();
if (!(tempX < 0 || tempZ < 0 || tempX >= vanillaRenderedChunks.length || tempZ >= vanillaRenderedChunks[0].length))
{
if (!vanillaRenderedChunks[tempX][tempZ])
{
return true;
}
}
else
{
if (vanillaRenderedChunks[x][z])
{
return true;
}
}
if (vanillaRenderedChunks[x][z] || (!(tempX < 0 || tempZ < 0 || tempX >= vanillaRenderedChunks.length || tempZ >= vanillaRenderedChunks[0].length)
&& !vanillaRenderedChunks[tempX][tempZ]))
return true;
}
return false;
}
@@ -128,7 +128,7 @@ public class ThreadMapUtil
int size = 1;
for (int i = 0; i < 5; i++)
{
array[i] = new long[size * size * DataPointUtil.worldHeight + 1];
array[i] = new long[size * size * DataPointUtil.worldHeight / 2 + 1];
size = size << 1;
}
threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array);
@@ -0,0 +1,64 @@
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;
//This class wraps the minecraft BlockPos.Mutable (and BlockPos) class
public class BlockPosWrapper
{
private BlockPos.Mutable blockPos;
public BlockPosWrapper()
{
this.blockPos = new BlockPos.Mutable();
}
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);
}
}
@@ -0,0 +1,276 @@
package com.seibel.lod.wrappers.Block;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
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.minecraftforge.client.model.data.ModelDataMap;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
//This class wraps the minecraft Block class
public class BlockWrapper
{
//set of block which require tint
public static final ConcurrentMap<Block, BlockWrapper> blockWrapperMap = new ConcurrentHashMap<>();
public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
public static Random random = new Random(0);
private Block block;
private boolean nonFull;
private boolean noCollision;
private int color;
private boolean isColored;
private boolean toTint;
private boolean leavesTint;
private boolean grassTint;
private boolean waterTint;
/**Constructor only require for the block instance we are wrapping**/
public BlockWrapper(Block block)
{
this.nonFull = true;
this.noCollision = true;
this.color = 0;
this.isColored = true;
this.toTint = false;
this.block = block;
setupColorAndTint();
setupShapes();
}
/**
* this return a wrapper of the block in input
* @param block Block object to wrap
*/
static public BlockWrapper getBlockWrapper(Block block)
{
//first we check if the block has already been wrapped
if(blockWrapperMap.containsKey(block) && blockWrapperMap.get(block) != null)
return blockWrapperMap.get(block);
//if it hasn't been created yet, we create it and save it in the map
BlockWrapper blockWrapper = new BlockWrapper(block);
blockWrapperMap.put(block, blockWrapper);
//we return the newly created wrapper
return blockWrapper;
}
/**
* Generate the color of the given block from its texture
* and store it for later use.
*/
private void setupColorAndTint()
{
MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
TextureAtlasSprite texture;
List<BakedQuad> quads = null;
boolean isTinted = false;
int listSize = 0;
// first step is to check if this block has a tinted face
for (Direction direction : Direction.values())
{
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(block.defaultBlockState(), direction, random, dataMap);
listSize = Math.max(listSize, quads.size());
for (BakedQuad bakedQuad : quads)
{
isTinted |= bakedQuad.isTinted();
}
}
//if it contains a tinted face then we store this block in the toTint set
if(isTinted)
this.toTint = true;
//now we get the first non empty face
for (Direction direction : Direction.values())
{
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(block.defaultBlockState(), direction, random, dataMap);
if (!quads.isEmpty())
break;
}
//the quads list is not empty we extract the first one
if (!quads.isEmpty())
texture = quads.get(0).getSprite();
else
{
return;
}
int count = 0;
int alpha = 0;
int red = 0;
int green = 0;
int blue = 0;
int numberOfGreyPixel = 0;
int tempColor;
int colorMultiplier;
// generate the block's color
for (int frameIndex = 0; frameIndex < texture.getFrameCount(); frameIndex++)
{
// textures normally use u and v instead of x and y
for (int u = 0; u < texture.getHeight(); u++)
{
for (int v = 0; v < texture.getWidth(); v++)
{
if (texture.isTransparent(frameIndex, u, v))
continue;
tempColor = texture.getPixelRGBA(frameIndex, u, v);
// determine if this pixel is gray
int colorMax = Math.max(Math.max(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
int colorMin = 4 + Math.min(Math.min(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
boolean isGray = colorMax < colorMin;
if (isGray)
numberOfGreyPixel++;
// for flowers, weight their non-green color higher
if (block instanceof FlowerBlock && (!(ColorUtil.getGreen(tempColor) > (ColorUtil.getBlue(tempColor) + 30)) || !(ColorUtil.getGreen(tempColor) > (ColorUtil.getRed(tempColor) + 30))))
colorMultiplier = 5;
else
colorMultiplier = 1;
// add to the running averages
count += colorMultiplier;
alpha += ColorUtil.getAlpha(tempColor) * colorMultiplier;
red += ColorUtil.getBlue(tempColor) * colorMultiplier;
green += ColorUtil.getGreen(tempColor) * colorMultiplier;
blue += ColorUtil.getRed(tempColor) * colorMultiplier;
}
}
}
if (count == 0)
// this block is entirely transparent
tempColor = 0;
else
{
// determine the average color
alpha /= count;
red /= count;
green /= count;
blue /= count;
tempColor = ColorUtil.rgbToInt(alpha, red, green, blue);
}
// determine if this block should use the biome color tint
if ((grassInstance() || leavesInstance() || waterIstance()) && (float) numberOfGreyPixel / count > 0.75f)
this.toTint = true;
// we check which kind of tint we need to apply
if (grassInstance() && this.toTint)
this.grassTint = true;
if (leavesInstance() && this.toTint)
this.leavesTint = true;
if (waterIstance() && this.toTint)
this.waterTint = true;
color = tempColor;
}
/** determine if the given block should use the biome's grass color */
private boolean grassInstance()
{
return block instanceof GrassBlock
|| block instanceof BushBlock
|| block instanceof IGrowable
|| block instanceof AbstractPlantBlock
|| block instanceof AbstractTopPlantBlock
|| block instanceof TallGrassBlock;
}
/** determine if the given block should use the biome's foliage color */
private boolean leavesInstance()
{
return block instanceof LeavesBlock
|| block == Blocks.VINE
|| block == Blocks.SUGAR_CANE;
}
/** determine if the given block should use the biome's foliage color */
private boolean waterIstance()
{
return block == Blocks.WATER;
}
private void setupShapes(){
}
//--------------//
//Colors getters//
//--------------//
public boolean hasColor()
{
return isColored;
}
public int getColor()
{
return color;
}
//------------//
//Tint getters//
//------------//
public boolean hasTint()
{
return toTint;
}
public boolean hasGrassTint()
{
return grassTint;
}
public boolean hasLeavesTint()
{
return leavesTint;
}
public boolean hasWaterTint()
{
return waterTint;
}
@Override public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof BlockWrapper))
return false;
BlockWrapper that = (BlockWrapper) o;
return Objects.equals(block, that.block);
}
@Override public int hashCode()
{
return Objects.hash(block);
}
}
@@ -0,0 +1,7 @@
package com.seibel.lod.wrappers.Chunk;
//This class will contain all methods usefull to generate the fake ChunkWrapper
public class ChunkGenerator
{
}
@@ -0,0 +1,44 @@
package com.seibel.lod.wrappers.Chunk;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import java.util.Objects;
//This class wraps the minecraft ChunkPos class
public class ChunkPosWrapper
{
private ChunkPos chunkPos;
public ChunkPosWrapper(ChunkPos chunkPos)
{
this.chunkPos = chunkPos;
}
public int getX()
{
return chunkPos.x;
}
public int getZ()
{
return chunkPos.z;
}
public ChunkPos getChunkPos()
{
return chunkPos;
}
@Override public boolean equals(Object o)
{
return chunkPos.equals(o);
}
@Override public int hashCode()
{
return Objects.hash(chunkPos);
}
}
@@ -0,0 +1,31 @@
package com.seibel.lod.wrappers.Chunk;
import com.seibel.lod.wrappers.Block.BlockWrapper;
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
import net.minecraft.world.chunk.IChunk;
public class ChunkWrapper
{
private IChunk chunk;
private ChunkPosWrapper chunkPos;
public ChunkWrapper(IChunk chunk)
{
this.chunk = chunk;
this.chunkPos = new ChunkPosWrapper(chunk.getPos());
}
public BlockWrapper getBlock(BlockPosWrapper blockPos)
{
return BlockWrapper.getBlockWrapper(chunk.getBlockState(blockPos.getBlockPos()).getBlock());
}
public ChunkPosWrapper getChunkPos(){
return chunkPos;
}
public int getEmittedBrightness(BlockPosWrapper blockPos)
{
return chunk.getLightEmission(blockPos.getBlockPos());
}
}
@@ -0,0 +1,19 @@
package com.seibel.lod.wrappers;
import net.minecraft.client.renderer.texture.NativeImage;
public class LigthMapWrapper
{
static NativeImage lightMap = null;
public static void setLightMap(NativeImage lightMap)
{
lightMap = null;
}
public static int getLightValue(int skyLight, int blockLight)
{
return lightMap.getPixelRGBA(skyLight, blockLight);
}
}
@@ -0,0 +1,5 @@
package com.seibel.lod.wrappers.Vertex;
public class BufferBuilderWrapper
{
}
@@ -0,0 +1,5 @@
package com.seibel.lod.wrappers.Vertex;
public class VertexBufferWrapper
{
}
@@ -0,0 +1,133 @@
package com.seibel.lod.wrappers.World;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.wrappers.Block.BlockWrapper;
import net.minecraft.block.Blocks;
import net.minecraft.world.biome.Biome;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
//This class wraps the minecraft BlockPos.Mutable (and BlockPos) class
public class BiomeWrapper
{
public static final ConcurrentMap<Biome, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
private Biome biome;
public BiomeWrapper(Biome biome)
{
this.biome = biome;
}
static public BiomeWrapper getBiomeWrapper(Biome biome)
{
//first we check if the biome has already been wrapped
if(biomeWrapperMap.containsKey(biome) && biomeWrapperMap.get(biome) != null)
return biomeWrapperMap.get(biome);
//if it hasn't been created yet, we create it and save it in the map
BiomeWrapper biomeWrapper = new BiomeWrapper(biome);
biomeWrapperMap.put(biome, biomeWrapper);
//we return the newly created wrapper
return biomeWrapper;
}
/** Returns a color int for the given biome. */
public int getColorForBiome(int x, int z)
{
int colorInt;
int color;
int tint;
switch (biome.getBiomeCategory())
{
case NETHER:
colorInt = BlockWrapper.getBlockWrapper(Blocks.NETHERRACK).getColor();
break;
case THEEND:
colorInt = BlockWrapper.getBlockWrapper(Blocks.END_STONE).getColor();
break;
case BEACH:
case DESERT:
colorInt = BlockWrapper.getBlockWrapper(Blocks.SAND).getColor();
break;
case EXTREME_HILLS:
colorInt = BlockWrapper.getBlockWrapper(Blocks.STONE).getColor();
break;
case MUSHROOM:
colorInt = BlockWrapper.getBlockWrapper(Blocks.MYCELIUM).getColor();
break;
case ICY:
colorInt = BlockWrapper.getBlockWrapper(Blocks.SNOW).getColor();
break;
case MESA:
colorInt = BlockWrapper.getBlockWrapper(Blocks.RED_SAND).getColor();
break;
case OCEAN:
case RIVER:
colorInt = biome.getWaterColor();
break;
case SWAMP:
case FOREST:
color = BlockWrapper.getBlockWrapper(Blocks.OAK_LEAVES).getColor();
tint = biome.getFoliageColor();
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
break;
case TAIGA:
color = BlockWrapper.getBlockWrapper(Blocks.SPRUCE_LEAVES).getColor();
tint = biome.getFoliageColor();
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
break;
case JUNGLE:
color = BlockWrapper.getBlockWrapper(Blocks.JUNGLE_LEAVES).getColor();
tint = biome.getFoliageColor();
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
break;
default:
case NONE:
case PLAINS:
case SAVANNA:
color = BlockWrapper.getBlockWrapper(Blocks.GRASS_BLOCK).getColor();
tint = biome.getGrassColor(x,z);
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
break;
}
return colorInt;
}
@Override public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof BiomeWrapper))
return false;
BiomeWrapper that = (BiomeWrapper) o;
return Objects.equals(biome, that.biome);
}
@Override public int hashCode()
{
return Objects.hash(biome);
}
}
@@ -0,0 +1,37 @@
package com.seibel.lod.wrappers.World;
import net.minecraft.world.DimensionType;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class DimensionTypeWrapper
{
private static final ConcurrentMap<DimensionType, DimensionTypeWrapper> dimensionTypeWrapperMap = new ConcurrentHashMap<>();
private DimensionType dimensionType;
public DimensionTypeWrapper(DimensionType dimensionType)
{
this.dimensionType = dimensionType;
}
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType)
{
//first we check if the biome has already been wrapped
if(dimensionTypeWrapperMap.containsKey(dimensionType) && dimensionTypeWrapperMap.get(dimensionType) != null)
return dimensionTypeWrapperMap.get(dimensionType);
//if it hasn't been created yet, we create it and save it in the map
DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType);
dimensionTypeWrapperMap.put(dimensionType, dimensionTypeWrapper);
//we return the newly created wrapper
return dimensionTypeWrapper;
}
public static void clearMap()
{
dimensionTypeWrapperMap.clear();
}
}
@@ -0,0 +1,68 @@
package com.seibel.lod.wrappers.World;
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
import net.minecraft.world.IWorld;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class WorldWrapper
{
private static final ConcurrentMap<IWorld, WorldWrapper> worldWrapperMap = new ConcurrentHashMap<>();
private IWorld world;
public WorldWrapper(IWorld world)
{
this.world = world;
}
public WorldWrapper getWorldWrapper(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
WorldWrapper worldWrapper = new WorldWrapper(world);
worldWrapperMap.put(world, worldWrapper);
//we return the newly created wrapper
return worldWrapper;
}
public static void clearMap()
{
worldWrapperMap.clear();
}
public DimensionTypeWrapper getDimensionType()
{
return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
}
public int getBlockLight(BlockPosWrapper blockPos)
{
return world.getLightEngine().skyEngine.getLightValue(blockPos.getBlockPos());
}
public int getSkyLight(BlockPosWrapper blockPos)
{
return world.getLightEngine().blockEngine.getLightValue(blockPos.getBlockPos());
}
public BiomeWrapper getBiome(BlockPosWrapper blockPos)
{
return BiomeWrapper.getBiomeWrapper(world.getBiome(blockPos.getBlockPos()));
}
public boolean hasCeiling()
{
return world.dimensionType().hasCeiling();
}
public boolean hasSkyLight()
{
return world.dimensionType().hasSkyLight();
}
}