diff --git a/src/main/java/com/seibel/lod/LodMain.java b/src/main/java/com/seibel/lod/LodMain.java index ec371c728..cd54212a9 100644 --- a/src/main/java/com/seibel/lod/LodMain.java +++ b/src/main/java/com/seibel/lod/LodMain.java @@ -1,10 +1,14 @@ package com.seibel.lod; +import org.lwjgl.opengl.GL; + import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.render.LodRenderer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.DeferredWorkQueue; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; @@ -20,7 +24,7 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; * check out the ClientProxy. * * @author James Seibel - * @version 02-07-2021 + * @version 7-3-2021 */ @Mod(ModInfo.MODID) public class LodMain @@ -30,9 +34,26 @@ public class LodMain public static ClientProxy client_proxy; + @SuppressWarnings("deprecation") private void init(final FMLCommonSetupEvent event) { ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, LodConfig.clientSpec); + + + Thread setFancyFog = new Thread(() -> + { + LodRenderer.fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance; + + if (!LodRenderer.fancyFogAvailable) + { + ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that fancy fog options will not be available."); + } + }); + + // This will be run on the main thread when it is able. + // If it wasn't run on the main thread GL.getCapabilities() + // would fail. + DeferredWorkQueue.runLater(setFancyFog); } diff --git a/src/main/java/com/seibel/lod/enums/FogDistance.java b/src/main/java/com/seibel/lod/enums/FogDistance.java index 4e0f7fa12..7f66d0acd 100644 --- a/src/main/java/com/seibel/lod/enums/FogDistance.java +++ b/src/main/java/com/seibel/lod/enums/FogDistance.java @@ -1,7 +1,7 @@ package com.seibel.lod.enums; /** - * Near, far, or NEAR_AND_FAR. + * NEAR, FAR, or NEAR_AND_FAR. * * @author James Seibel * @version 02-14-2021 @@ -10,8 +10,10 @@ public enum FogDistance { /** good for fast or fancy fog qualities. */ NEAR, + /** good for fast or fancy fog qualities. */ FAR, + /** only looks good if the fog quality is set to Fancy. */ NEAR_AND_FAR; } \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/enums/FogDrawOverride.java b/src/main/java/com/seibel/lod/enums/FogDrawOverride.java new file mode 100644 index 000000000..3b85b0760 --- /dev/null +++ b/src/main/java/com/seibel/lod/enums/FogDrawOverride.java @@ -0,0 +1,26 @@ +package com.seibel.lod.enums; + +/** + * USE_OPTIFINE_FOG_SETTING,
+ * NEVER_DRAW_FOG,
+ * ALWAYS_DRAW_FOG_FAST,
+ * ALWAYS_DRAW_FOG_FANCY
+ * + * @author James Seibel + * @version 7-03-2021 + */ +public enum FogDrawOverride +{ + /** Use whatever Fog setting optifine is using. + * If optifine isn't installed this defaults to ALWAYS_DRAW_FOG. */ + USE_OPTIFINE_FOG_SETTING, + + /** Never draw fog on the LODs */ + NEVER_DRAW_FOG, + + /** Always draw fog on the LODs */ + ALWAYS_DRAW_FOG_FAST, + + /** Always draw fog on the LODs */ + ALWAYS_DRAW_FOG_FANCY; +} \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/handlers/LodConfig.java b/src/main/java/com/seibel/lod/handlers/LodConfig.java index 95380cff9..43fa3b067 100644 --- a/src/main/java/com/seibel/lod/handlers/LodConfig.java +++ b/src/main/java/com/seibel/lod/handlers/LodConfig.java @@ -11,6 +11,7 @@ import com.electronwill.nightconfig.core.io.WritingMode; import com.seibel.lod.ModInfo; import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.enums.FogDistance; +import com.seibel.lod.enums.FogDrawOverride; import com.seibel.lod.enums.LodDetail; import com.seibel.lod.enums.LodTemplate; @@ -33,6 +34,8 @@ public class LodConfig public ForgeConfigSpec.EnumValue fogDistance; + public ForgeConfigSpec.EnumValue fogDrawOverride; + public ForgeConfigSpec.BooleanValue debugMode; public ForgeConfigSpec.EnumValue lodTemplate; @@ -53,22 +56,31 @@ public class LodConfig .comment("\n\n" + " If false LODs will not be drawn, \n" + " however they will still be generated \n" - + " and saved to file for later use.") + + " and saved to file for later use. \n") .define("drawLODs", true); fogDistance = builder .comment("\n\n" + " At what distance should Fog be drawn on the LODs? \n" + " If the fog cuts off ubruptly or you are using Optifine's \"fast\" \n" - + " fog option set this to " + FogDistance.NEAR.toString() + " or " + FogDistance.FAR.toString() + ".") + + " fog option set this to " + FogDistance.NEAR.toString() + " or " + FogDistance.FAR.toString() + ". \n") .defineEnum("fogDistance", FogDistance.NEAR_AND_FAR); + fogDrawOverride = builder + .comment("\n\n" + + " When should fog be drawn? \n" + + " " + FogDrawOverride.USE_OPTIFINE_FOG_SETTING.toString() + ": Use whatever Fog setting Optifine is using. If Optifine isn't installed this defaults to " + FogDrawOverride.ALWAYS_DRAW_FOG_FANCY.toString() + ". \n" + + " " + FogDrawOverride.NEVER_DRAW_FOG.toString() + ": Never draw fog on the LODs \n" + + " " + FogDrawOverride.ALWAYS_DRAW_FOG_FAST.toString() + ": Always draw fast fog on the LODs \n" + + " " + FogDrawOverride.ALWAYS_DRAW_FOG_FANCY.toString() + ": Always draw fancy fog on the LODs (if your graphics card supports it) \n") + .defineEnum("fogDrawOverride", FogDrawOverride.USE_OPTIFINE_FOG_SETTING); + debugMode = builder .comment("\n\n" + " If false the LODs will draw with their normal world colors. \n" + " If true they will draw as a black and white checkerboard. \n" + " This can be used for debugging or imagining you are playing a \n" - + " giant game of chess ;)") + + " giant game of chess ;) \n") .define("drawCheckerBoard", false); lodTemplate = builder @@ -77,14 +89,16 @@ public class LodConfig + " " + LodTemplate.CUBIC.toString() + ": LOD Chunks are drawn as rectangular prisms (boxes). \n" + " " + LodTemplate.TRIANGULAR.toString() + ": LOD Chunks smoothly transition between other. \n" + " " + LodTemplate.DYNAMIC.toString() + ": LOD Chunks smoothly transition between other, \n" - + " " + " unless a neighboring chunk is at a significantly different height. ") + + " " + " unless a neighboring chunk is at a significantly different height. \n") .defineEnum("lodTemplate", LodTemplate.CUBIC); lodDetail = builder .comment("\n\n" + " How detailed should the LODs be? \n" + " " + LodDetail.SINGLE.toString() + ": render 1 LOD for each Chunk. \n" - + " " + LodDetail.DOUBLE.toString() + ": render 4 LODs for each Chunk.") + + " " + LodDetail.DOUBLE.toString() + ": render 4 LODs for each Chunk. \n" + + " " + LodDetail.QUAD.toString() + ": render 16 LODs for each Chunk. \n" + + " " + LodDetail.HALF.toString() + ": render 64 LODs for each Chunk. \n") .defineEnum("lodGeometryQuality", LodDetail.QUAD); lodChunkRadiusMultiplier = builder @@ -92,14 +106,15 @@ public class LodConfig + " This is multiplied by the default view distance \n" + " to determine how far out to generate/render LODs. \n" + " A value of 2 means that there is 1 render distance worth \n" - + " of LODs in each cardinal direction. ") + + " of LODs in each cardinal direction. \n") .defineInRange("lodChunkRadiusMultiplier", 6, 2, 32); distanceGenerationMode = builder .comment("\n\n" - + " Note: The times listed here are based on the developer's \n" - + " PC, and are included to show the speed difference \n" - + " between options. Your mileage may vary. \n" + + " Note: The times listed here are the amount of time it took" + + " the developer's PC to generate 1 chunk, \n" + + " and are included so you can compare the \n" + + " different generation options. Your mileage may vary. \n" + "\n" + " " + DistanceGenerationMode.BIOME_ONLY.toString() + " \n" diff --git a/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java b/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java index fd3f320be..77fc60e27 100644 --- a/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java +++ b/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java @@ -12,14 +12,13 @@ import net.minecraft.client.Minecraft; * in Optifine. * * @author James Seibel - * @version 09-21-2020 + * @version 7-03-2021 */ public class ReflectionHandler { private Minecraft mc = Minecraft.getInstance(); public Field ofFogField = null; - public ReflectionHandler() { setupFogField(); @@ -34,14 +33,14 @@ public class ReflectionHandler private void setupFogField() { // get every variable from the entity renderer - Field[] vars = mc.options.getClass().getDeclaredFields(); + Field[] optionFields = mc.options.getClass().getDeclaredFields(); // try and find the ofFogType variable in gameSettings - for(Field f : vars) + for(Field field : optionFields) { - if(f.getName().equals("ofFogType")) + if(field.getName().equals("ofFogType")) { - ofFogField = f; + ofFogField = field; return; } } @@ -82,8 +81,12 @@ public class ReflectionHandler switch (returnNum) { + // optifine's "default" option, + // it should never be called in this case case 0: return FogQuality.FAST; + + // normal options case 1: return FogQuality.FAST; case 2: diff --git a/src/main/java/com/seibel/lod/objects/NearFarFogSetting.java b/src/main/java/com/seibel/lod/objects/NearFarFogSetting.java deleted file mode 100644 index 5e7c2383a..000000000 --- a/src/main/java/com/seibel/lod/objects/NearFarFogSetting.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.seibel.lod.objects; - -import com.seibel.lod.enums.FogDistance; - -/** - * This object is just a replacement for an array - * to make things easier to understand in the LodRenderer. - * - * @author James Seibel - * @version 02-27-2021 - */ -public class NearFarFogSetting -{ - public FogDistance nearFogSetting = FogDistance.NEAR; - public FogDistance farFogSetting = FogDistance.FAR; - - - public NearFarFogSetting() - { - - } - - public NearFarFogSetting(FogDistance newNearFogSetting, FogDistance newFarFogSetting) - { - nearFogSetting = newNearFogSetting; - farFogSetting = newFarFogSetting; - } -} diff --git a/src/main/java/com/seibel/lod/objects/NearFarFogSettings.java b/src/main/java/com/seibel/lod/objects/NearFarFogSettings.java new file mode 100644 index 000000000..52da46a13 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/NearFarFogSettings.java @@ -0,0 +1,46 @@ +package com.seibel.lod.objects; + +import com.seibel.lod.enums.FogDistance; +import com.seibel.lod.enums.FogQuality; + +/** + * This object is just a replacement for an array + * to make things easier to understand in the LodRenderer. + * + * @author James Seibel + * @version 7-03-2021 + */ +public class NearFarFogSettings +{ + public NearOrFarSetting near = new NearOrFarSetting(FogDistance.NEAR); + public NearOrFarSetting far = new NearOrFarSetting(FogDistance.FAR); + + /** If true that means Minecraft is + * rendering fog along side us */ + public boolean vanillaIsRenderingFog = true; + + public NearFarFogSettings() + { + + } + + + + /** + * This holds all relevant data to rendering fog at either + * near or far distances. + */ + public class NearOrFarSetting + { + public FogQuality quality = FogQuality.FANCY; + public FogDistance distance = FogDistance.FAR; + + /** If true this section should render with fog */ + public boolean enabled = true; + + public NearOrFarSetting(FogDistance newFogDistance) + { + distance = newFogDistance; + } + } +} diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index e7d2e148d..0871339d5 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -99,7 +99,8 @@ public class ClientProxy // LodConfig.CLIENT.lodColorStyle.set(LodColorStyle.INDIVIDUAL_SIDES); // LodConfig.CLIENT.lodChunkRadiusMultiplier.set(12); // LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.FEATURES); -// LodConfig.CLIENT.fogDistance.set(FogDistance.FAR); +// LodConfig.CLIENT.fogDistance.set(FogDistance.NEAR_AND_FAR); +// LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.USE_OPTIFINE_FOG_SETTING); // Note to self: // if "unspecified" shows up in the pie chart, it is diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index b6d84f4c5..11e855a11 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -6,19 +6,21 @@ import java.nio.FloatBuffer; import java.util.HashSet; import org.lwjgl.opengl.GL11; +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.LodBufferBuilder; import com.seibel.lod.enums.FogDistance; +import com.seibel.lod.enums.FogDrawOverride; import com.seibel.lod.enums.FogQuality; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.handlers.ReflectionHandler; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.NearFarBuffer; -import com.seibel.lod.objects.NearFarFogSetting; +import com.seibel.lod.objects.NearFarFogSettings; import com.seibel.lod.proxy.ClientProxy; import net.minecraft.client.Minecraft; @@ -67,6 +69,10 @@ public class LodRenderer */ public static final int MAX_ALOCATEABLE_DIRECT_MEMORY = 64 * 1024 * 1024; + /** Does this computer's GPU support fancy fog? */ + public static boolean fancyFogAvailable = false; + + /** If true the LODs colors will be replaced with * a checkerboard, this can be used for debugging. */ @@ -93,6 +99,7 @@ public class LodRenderer private volatile VertexBuffer farVbo; public static final VertexFormat LOD_VERTEX_FORMAT = DefaultVertexFormats.POSITION_COLOR; + /** This is used to determine if the LODs should be regenerated */ private int previousChunkRenderDistance = 0; /** This is used to determine if the LODs should be regenerated */ @@ -266,14 +273,14 @@ public class LodRenderer setupProjectionMatrix(partialTicks); setupLighting(lodDim, partialTicks); - NearFarFogSetting fogSetting = determineFogSettings(); + NearFarFogSettings fogSettings = determineFogSettings(); // 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); @@ -285,10 +292,10 @@ public class LodRenderer //===========// profiler.popPush("LOD draw"); - setupFog(fogSetting.nearFogSetting, reflectionHandler.getFogQuality()); + setupFog(fogSettings.near.distance, fogSettings.near.quality); sendLodsToGpuAndDraw(nearVbo, modelViewMatrix); - setupFog(fogSetting.farFogSetting, reflectionHandler.getFogQuality()); + setupFog(fogSettings.far.distance, fogSettings.far.quality); sendLodsToGpuAndDraw(farVbo, modelViewMatrix); @@ -315,9 +322,7 @@ public class LodRenderer // reset the fog settings so the normal chunks // will be drawn correctly - RenderSystem.fogStart(defaultFogStartDist); - RenderSystem.fogEnd(defaultFogEndDist); - RenderSystem.fogMode(defaultFogMode); + cleanupFog(fogSettings, defaultFogStartDist, defaultFogEndDist, defaultFogMode, defaultFogDistance); // reset the projection matrix so anything drawn after // the LODs will use the correct projection matrix @@ -380,10 +385,24 @@ public class LodRenderer { throw new IllegalArgumentException("setupFog doesn't accept the NEAR_AND_FAR fog distance."); } - + + + // determine the fog distance mode to use + int glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV; + if (fogQuality == FogQuality.FANCY) + { + // fancy fog (fragment distance based fog) + glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV; + } + else + { + // fast fog (frustum distance based fog) + glFogDistanceMode = NVFogDistance.GL_EYE_PLANE_ABSOLUTE_NV; + } + + // the multipliers are percentages // of the regular view distance. - if(fogDistance == FogDistance.NEAR) { // the reason that I wrote fogEnd then fogStart backwards @@ -420,8 +439,34 @@ public class LodRenderer } } - RenderSystem.fogMode(GlStateManager.FogMode.LINEAR); + + GL11.glEnable(GL11.GL_FOG); RenderSystem.enableFog(); + RenderSystem.setupNvFogDistance(); + RenderSystem.fogMode(GlStateManager.FogMode.LINEAR); + GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, glFogDistanceMode); + } + + /** + * Revert any changes that were made to the fog. + */ + private void cleanupFog(NearFarFogSettings fogSettings, + float defaultFogStartDist, float defaultFogEndDist, + int defaultFogMode, int defaultFogDistance) + { + 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)) + { + GL11.glDisable(GL11.GL_FOG); + } } @@ -614,68 +659,114 @@ public class LodRenderer /** - * Based on the fogDistance setting and - * optifine's fogQuality setting return what fog - * settings should be used when rendering. + * Return what fog settings should be used when rendering. */ - private NearFarFogSetting determineFogSettings() + private NearFarFogSettings determineFogSettings() { - NearFarFogSetting fogSetting = new NearFarFogSetting(); + NearFarFogSettings fogSettings = new NearFarFogSettings(); - switch(reflectionHandler.getFogQuality()) + + FogQuality quality = reflectionHandler.getFogQuality(); + FogDrawOverride override = LodConfig.CLIENT.fogDrawOverride.get(); + + + if (quality == FogQuality.OFF) + fogSettings.vanillaIsRenderingFog = false; + else + fogSettings.vanillaIsRenderingFog = true; + + + // use any fog overrides the user may have set + switch(override) + { + case ALWAYS_DRAW_FOG_FANCY: + quality = FogQuality.FANCY; + break; + + case NEVER_DRAW_FOG: + quality = FogQuality.OFF; + break; + + case ALWAYS_DRAW_FOG_FAST: + quality = FogQuality.FAST; + break; + + case USE_OPTIFINE_FOG_SETTING: + // don't override anything + break; + } + + + // only use fancy fog if the user's GPU can deliver + if (!fancyFogAvailable && quality == FogQuality.FANCY) + { + quality = FogQuality.FAST; + } + + + // how different distances are drawn depends on the quality set + switch(quality) { case FANCY: + fogSettings.near.quality = FogQuality.FANCY; + fogSettings.far.quality = FogQuality.FANCY; switch(LodConfig.CLIENT.fogDistance.get()) { case NEAR_AND_FAR: - fogSetting.nearFogSetting = FogDistance.NEAR; - fogSetting.farFogSetting = FogDistance.FAR; + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.FAR; break; case NEAR: - fogSetting.nearFogSetting = FogDistance.NEAR; - fogSetting.farFogSetting = FogDistance.NEAR; + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.NEAR; break; case FAR: - fogSetting.nearFogSetting = FogDistance.FAR; - fogSetting.farFogSetting = FogDistance.FAR; + fogSettings.near.distance = FogDistance.FAR; + fogSettings.far.distance = FogDistance.FAR; break; } - break; + case FAST: + fogSettings.near.quality = FogQuality.FAST; + fogSettings.far.quality = FogQuality.FAST; + // fast fog setting should only have one type of // fog, since the LODs are separated into a near // and far portion; and fast fog is rendered from the // frustrum's perspective instead of the camera - switch(LodConfig.CLIENT.fogDistance.get()) { case NEAR_AND_FAR: - fogSetting.nearFogSetting = FogDistance.NEAR; - fogSetting.farFogSetting = FogDistance.NEAR; + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.NEAR; break; case NEAR: - fogSetting.nearFogSetting = FogDistance.NEAR; - fogSetting.farFogSetting = FogDistance.NEAR; + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.NEAR; break; case FAR: - fogSetting.nearFogSetting = FogDistance.FAR; - fogSetting.farFogSetting = FogDistance.FAR; + fogSettings.near.distance = FogDistance.FAR; + fogSettings.far.distance = FogDistance.FAR; break; } + break; - break; case OFF: + + fogSettings.near.quality = FogQuality.OFF; + fogSettings.far.quality = FogQuality.OFF; break; - + } - return fogSetting; + + return fogSettings; }