From 1c7d87b9d3ebfffad683771ff48ce88364309327 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Sun, 13 Mar 2022 15:39:34 +0800 Subject: [PATCH 01/13] Add new config: Biome Blending --- .../bufferBuilding/CubicLodTemplate.java | 35 +++++-------------- .../config/ILodConfigWrapperSingleton.java | 34 +++++++----------- src/main/resources/assets/lod/lang/en_us.json | 16 ++++----- 3 files changed, 27 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/CubicLodTemplate.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/CubicLodTemplate.java index 3f7e64a46..f90dcea43 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/CubicLodTemplate.java @@ -19,16 +19,12 @@ package com.seibel.lod.core.builders.bufferBuilding; -import java.awt.Color; - import com.seibel.lod.core.enums.rendering.DebugMode; -import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; import com.seibel.lod.core.objects.opengl.LodBox; import com.seibel.lod.core.objects.opengl.LodQuadBuilder; import com.seibel.lod.core.util.DataPointUtil; import com.seibel.lod.core.util.LevelPosUtil; import com.seibel.lod.core.util.LodUtil; -import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; /** * Builds LODs as rectangular prisms. @@ -36,14 +32,10 @@ import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; * @author James Seibel * @version 12-8-2021 */ -public class CubicLodTemplate -{ - private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); - - +public class CubicLodTemplate { + public static void addLodToBuffer(long data, long topData, long botData, long[][][] adjData, byte detailLevel, - int offsetPosX, int offsetOosZ, LodQuadBuilder quadBuilder, DebugMode debugging) - { + int offsetPosX, int offsetOosZ, LodQuadBuilder quadBuilder, DebugMode debugging) { short width = (short) (1 << detailLevel); short x = (short) LevelPosUtil.convert(detailLevel, offsetPosX, LodUtil.BLOCK_DETAIL_LEVEL); short y = DataPointUtil.getDepth(data); @@ -51,28 +43,17 @@ public class CubicLodTemplate short dy = (short) (DataPointUtil.getHeight(data) - y); if (dy == 0) return; - + int color; - if (debugging != DebugMode.OFF && debugging != DebugMode.SHOW_WIREFRAME) - { + if (debugging != DebugMode.OFF && debugging != DebugMode.SHOW_WIREFRAME) { if (debugging == DebugMode.SHOW_DETAIL || debugging == DebugMode.SHOW_DETAIL_WIREFRAME) color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB(); else /// if (debugging == DebugMode.SHOW_GENMODE || debugging == /// DebugMode.SHOW_GENMODE_WIREFRAME) color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)].getRGB(); - } - else - { - double saturationMultiplier = CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier(); - double brightnessMultiplier = CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier(); - - Color colorObject = LodUtil.intToColor(DataPointUtil.getColor(data)); - - float[] hsb = Color.RGBtoHSB(colorObject.getRed(), colorObject.getGreen(), colorObject.getBlue(), null); - color = LodUtil.colorToInt(Color.getHSBColor(hsb[0], (float) LodUtil.clamp(0.0f, hsb[1] * saturationMultiplier, 1.0f), (float) LodUtil.clamp(0.0f, hsb[2] * brightnessMultiplier, 1.0f))); - - } - + } else + color = DataPointUtil.getColor(data); + LodBox.addBoxQuadsToBuilder(quadBuilder, // buffer width, dy, width, // setWidth x, y, z, // setOffset diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index 8510d2fa8..b40f8aa23 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -169,7 +169,19 @@ public interface ILodConfigWrapperSingleton extends IBindable DropoffQuality.SMOOTH_DROPOFF : DropoffQuality.PERFORMANCE_FOCUSED; return dropoffQuality; } - + + MinDefaultMax LOD_BIOME_BLENDING_MIN_DEFAULT_MAX = new MinDefaultMax(0,0,7); + String LOD_BIOME_BLENDING_DESC = "" + + " This is the same as vanilla Biome Blending settings for Lod area. \n" + + " Note that anything other than '0' will greatly effect Lod building time \n" + + " and increase triangle count. The cost on chunk generation speed is also \n" + + " quite large if set to too high.\n" + + "\n" + + " '0' equals to Vanilla Biome Blending of '1x1', \n" + + " '1' equals to Vanilla Biome Blending of '3x3', \n" + + " '2' equals to Vanilla Biome Blending of '5x5'... \n"; + int getLodBiomeBlending(); + void setLodBiomeBlending(int newLodBiomeBlending); } interface IFogQuality @@ -310,26 +322,6 @@ public interface ILodConfigWrapperSingleton extends IBindable + " This setting shouldn't affect performance. \n"; boolean getUseExtendedNearClipPlane(); void setUseExtendedNearClipPlane(boolean newUseExtendedNearClipPlane); - - double BRIGHTNESS_MULTIPLIER_DEFAULT = 1.0; - String BRIGHTNESS_MULTIPLIER_DESC = "" - + " How bright fake chunk colors are. \n" - + "\n" - + " 0 = black \n" - + " 1 = normal \n" - + " 2 = near white \n"; - double getBrightnessMultiplier(); - void setBrightnessMultiplier(double newBrightnessMultiplier); - - double SATURATION_MULTIPLIER_DEFAULT = 1.0; - String SATURATION_MULTIPLIER_DESC = "" - + " How saturated fake chunk colors are. \n" - + "\n" - + " 0 = black and white \n" - + " 1 = normal \n" - + " 2 = very saturated \n"; - double getSaturationMultiplier(); - void setSaturationMultiplier(double newSaturationMultiplier); } } diff --git a/src/main/resources/assets/lod/lang/en_us.json b/src/main/resources/assets/lod/lang/en_us.json index 230a0f91c..962170490 100644 --- a/src/main/resources/assets/lod/lang/en_us.json +++ b/src/main/resources/assets/lod/lang/en_us.json @@ -37,6 +37,10 @@ "Dropoff quality", "DistantHorizons.config.client.graphics.quality.dropoffQuality.@tooltip": "How detail dropoff is calculated.\n\nHigher settings will make the drop-off less noticeable\nbut will increase how often the geometry has to be rebuilt,\nincreasing CPU usage and the chance of stuttering.", + "DistantHorizons.config.client.graphics.quality.lodBiomeBlending": + "Biome Blending", + "DistantHorizons.config.client.graphics.quality.lodBiomeBlending.@tooltip": + "This is the same as vanilla Biome Blending settings for Lod area. \n\nNote that anything other than '0' will greatly effect Lod building time\nand increase triangle count. The cost on chunk generation speed is also \nquite large if set to too high.\n\n'0' equals to Vanilla Biome Blending of '1x1', \n'1' equals to Vanilla Biome Blending of '3x3', \n'2' equals to Vanilla Biome Blending of '5x5'... \n", "DistantHorizons.config.client.graphics.fogQuality": "Fog options", "DistantHorizons.config.client.graphics.fogQuality.fogDistance": @@ -56,7 +60,7 @@ "DistantHorizons.config.client.graphics.fogQuality.disableVanillaFog.@tooltip": "§6True:§r disables Minecraft's fog on vanilla chunks.\n§6False:§r Minecraft renders fog like normal.\n\nMay cause issues with other mods that edit fog.\nDisable if vanilla chunks are completely covered in fog.", "DistantHorizons.config.client.graphics.advancedGraphics": - "Advanced Graphics", + "Advanced quality option", "DistantHorizons.config.client.graphics.advancedGraphics.lodTemplate": "LOD template", "DistantHorizons.config.client.graphics.advancedGraphics.lodTemplate.@tooltip": @@ -81,14 +85,6 @@ "Backside Culling Range", "DistantHorizons.config.client.graphics.advancedGraphics.backsideCullingRange.@tooltip": "The distance where the back side of fake chunks aren't rendered to improve performance.", - "DistantHorizons.config.client.graphics.advancedGraphics.brightnessMultiplier": - "Brightness Multiplier", - "DistantHorizons.config.client.graphics.advancedGraphics.brightnessMultiplier.@tooltip": - "How bright fake chunk colors are.\n\n0 = black \n1 = normal \n2 = near white", - "DistantHorizons.config.client.graphics.advancedGraphics.saturationMultiplier": - "Saturation Multiplier", - "DistantHorizons.config.client.graphics.advancedGraphics.saturationMultiplier.@tooltip": - "How saturated fake chunk colors are.\n\n0 = black and white \n1 = normal \n2 = vibrant", "DistantHorizons.config.client.worldGenerator": "World generator", "DistantHorizons.config.client.worldGenerator.generationPriority": @@ -122,7 +118,7 @@ "DistantHorizons.config.client.multiplayer.serverFolderNameMode.@tooltip": "Determines the folder format for local multiplayer data.\n\n§6Auto:§r\nUses \"Name, IP\" for LAN worlds and \"Name, IP, Port\" for standard multiplayer.\n§6Name Only:§r\nUses the server browser name. Ex: \"Minecraft Server\"\n§6Name IP:§r\n\"Minecraft Server, IP 192.168.1.40\"\n§6Name, IP, Port:§r\n\"Minecraft Server, IP 192.168.1.40:25565\"\n§6Name, IP, Port, MC Version:§r\n\"Minecraft Server, IP 192.168.1.40:25565, GameVersion 1.18.1\"\n\n§c§lCaution:§r changing while connected to a multiplayer server may cause glitches.", "DistantHorizons.config.client.advanced": - "Advanced Options", + "Advance options", "DistantHorizons.config.client.advanced.threading": "Threading", "DistantHorizons.config.client.advanced.threading.numberOfWorldGenerationThreads": From 49cc46dc25b1307e3e1fc8f2d13a9288c33674f8 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Sun, 13 Mar 2022 16:15:28 +0800 Subject: [PATCH 02/13] Update Config defaults --- .../config/ILodConfigWrapperSingleton.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index b40f8aa23..8c652f168 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -170,14 +170,14 @@ public interface ILodConfigWrapperSingleton extends IBindable return dropoffQuality; } - MinDefaultMax LOD_BIOME_BLENDING_MIN_DEFAULT_MAX = new MinDefaultMax(0,0,7); + MinDefaultMax LOD_BIOME_BLENDING_MIN_DEFAULT_MAX = new MinDefaultMax(0,1,7); String LOD_BIOME_BLENDING_DESC = "" + " This is the same as vanilla Biome Blending settings for Lod area. \n" + " Note that anything other than '0' will greatly effect Lod building time \n" + " and increase triangle count. The cost on chunk generation speed is also \n" + - " quite large if set to too high.\n" + + " quite large if set too high.\n" + "\n" + - " '0' equals to Vanilla Biome Blending of '1x1', \n" + + " '0' equals to Vanilla Biome Blending of '1x1' or 'OFF', \n" + " '1' equals to Vanilla Biome Blending of '3x3', \n" + " '2' equals to Vanilla Biome Blending of '5x5'... \n"; int getLodBiomeBlending(); From fbd8f48433749607b38789b597f7a7c12425faff Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Sun, 13 Mar 2022 22:57:06 +0800 Subject: [PATCH 03/13] Improved getMaximumRenderedChunk and fix GLMessage on forge --- .../com/seibel/lod/core/util/GLMessage.java | 36 +++++++++++++++++-- .../minecraft/IMinecraftRenderWrapper.java | 20 ++++++++--- .../world/IWorldWrapper.java | 2 +- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/util/GLMessage.java b/src/main/java/com/seibel/lod/core/util/GLMessage.java index fa4ca2106..57e7a0b97 100644 --- a/src/main/java/com/seibel/lod/core/util/GLMessage.java +++ b/src/main/java/com/seibel/lod/core/util/GLMessage.java @@ -1,5 +1,7 @@ package com.seibel.lod.core.util; +import org.lwjgl.system.CallbackI; + import java.util.HashMap; import java.util.function.Function; @@ -10,6 +12,32 @@ public final class GLMessage { public final GLMessage.Source source; public final String id; public final String message; + + // This is needed since gl callback will not have the correct class loader set, and causes issues. + static void initLoadClass() { + Builder dummy = new Builder(); + dummy.add(GLMessage.HEADER); + dummy.add("ID"); + dummy.add(":"); + dummy.add("dummyId"); + dummy.add("Source"); + dummy.add(":"); + dummy.add(Source.API.str); + dummy.add("Type"); + dummy.add(":"); + dummy.add(Type.OTHER.str); + dummy.add("Severity"); + dummy.add(":"); + dummy.add(Severity.LOW.str); + dummy.add("Message"); + dummy.add(":"); + dummy.add("dummyMessage"); + } + + static { + initLoadClass(); + } + GLMessage(GLMessage.Type t, GLMessage.Severity s, GLMessage.Source sr, String id, String ms) { this.type = t; this.source = sr; @@ -21,8 +49,7 @@ public final class GLMessage { public String toString() { return "[level:"+severity+", type:"+type+", source:"+source+", id:"+id+", msg:{"+message+"}]"; } - - + public enum Type { ERROR, DEPRECATED_BEHAVIOR, @@ -34,7 +61,7 @@ public final class GLMessage { POP_GROUP, OTHER; public final String str; - private Type() { + Type() { str = super.toString().toUpperCase(); } @Override @@ -93,6 +120,9 @@ public final class GLMessage { } public static class Builder { + static { + initLoadClass(); + } GLMessage.Type type; GLMessage.Severity severity; GLMessage.Source source; diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java index 90b223bc2..0297909ae 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java @@ -33,6 +33,7 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper; import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor; +import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper; /** * Contains everything related to @@ -82,7 +83,13 @@ public interface IMinecraftRenderWrapper extends IBindable ISodiumAccessor sodium = ModAccessorHandler.get(ISodiumAccessor.class); return sodium==null ? getMaximumRenderedChunks() : sodium.getNormalRenderedChunks(); } - + + private static boolean correctedCheckRadius(int dx, int dz, int radius2Mul4) { + dx = dx*2;// + (dx < 0 ? -1 : 1); + dz = dz*2;// + (dz < 0 ? -1 : 1); + return (dx*dx + dz*dz <= radius2Mul4); + } + /** * Doesn't need to be implemented.
* Returns every chunk position within the vanilla render distance. @@ -92,13 +99,15 @@ public interface IMinecraftRenderWrapper extends IBindable IMinecraftClientWrapper mcWrapper = SingletonHandler.get(IMinecraftClientWrapper.class); IWrapperFactory factory = SingletonHandler.get(IWrapperFactory.class); IVersionConstants versionConstants = SingletonHandler.get(IVersionConstants.class); - - int chunkDist = this.getRenderDistance(); + IMinecraftClientWrapper minecraft = SingletonHandler.get(IMinecraftClientWrapper.class); + IWorldWrapper clientWorld = minecraft.getWrappedClientWorld(); + + int chunkDist = this.getRenderDistance() + 1; // For some reason having '+1' is actually closer to real value AbstractChunkPosWrapper centerChunkPos = mcWrapper.getPlayerChunkPos(); int centerChunkX = centerChunkPos.getX(); int centerChunkZ = centerChunkPos.getZ(); - int chunkDist2 = chunkDist*chunkDist; + int chunkDist2Mul4 = chunkDist*chunkDist*4; // add every position within render distance HashSet renderedPos = new HashSet(); @@ -107,9 +116,10 @@ public interface IMinecraftRenderWrapper extends IBindable for(int deltaChunkZ = -chunkDist; deltaChunkZ <= chunkDist; deltaChunkZ++) { if (!versionConstants.isVanillaRenderedChunkSquare() && - deltaChunkX*deltaChunkX+deltaChunkZ*deltaChunkZ > chunkDist2) { + !correctedCheckRadius(deltaChunkX,deltaChunkZ,chunkDist2Mul4)) { continue; } + if (!clientWorld.hasChunkLoaded(centerChunkX + deltaChunkX, centerChunkZ + deltaChunkZ)) continue; renderedPos.add(factory.createChunkPos(centerChunkX + deltaChunkX, centerChunkZ + deltaChunkZ)); } } diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/world/IWorldWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/world/IWorldWrapper.java index 59a84ac5b..af6995fad 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/world/IWorldWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/world/IWorldWrapper.java @@ -60,5 +60,5 @@ public interface IWorldWrapper extends IBindable default IChunkWrapper tryGetChunk(AbstractChunkPosWrapper pos) {return null;} - + boolean hasChunkLoaded(int chunkX, int chunkZ); } From f1eb06bbb1eb075b7fa0d5bcd1fff63791f035a8 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:36:42 +0800 Subject: [PATCH 04/13] Fix nullptr exception on calling `clear(d)` with `d` being `null` (Thx @HyperSoop) --- .../lod/core/util/MovableGridRingList.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/util/MovableGridRingList.java b/src/main/java/com/seibel/lod/core/util/MovableGridRingList.java index e12750fa0..efd8cbb2c 100644 --- a/src/main/java/com/seibel/lod/core/util/MovableGridRingList.java +++ b/src/main/java/com/seibel/lod/core/util/MovableGridRingList.java @@ -32,24 +32,17 @@ public class MovableGridRingList extends ArrayList implements List { @Override public void clear() { - moveLock.writeLock().lock(); - try { - super.clear(); - super.ensureCapacity(size*size); - for (int i=0; i d) { moveLock.writeLock().lock(); try { - super.forEach((t) -> { - if (t!=null) d.accept(t); - }); + if (d != null) { + super.forEach((t) -> { + if (t!=null) d.accept(t); + }); + } super.clear(); super.ensureCapacity(size*size); for (int i=0; i Date: Mon, 14 Mar 2022 15:10:04 +0800 Subject: [PATCH 05/13] Fix hasCliffFace() not crossing chunk boundaries. Also temp added cave culling. Need logic to provide better cave culling. --- .../seibel/lod/core/builders/lodBuilding/LodBuilder.java | 6 +----- .../seibel/lod/core/objects/opengl/LodQuadBuilder.java | 9 +++++++++ .../lod/core/wrapperInterfaces/chunk/IChunkWrapper.java | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index b18fa9e54..f81b1b103 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -360,11 +360,7 @@ public class LodBuilder private boolean hasCliffFace(IChunkWrapper chunk, int x, int y, int z) { for (LodDirection dir : DIRECTIONS) { - int cx = x+dir.getNormal().x; - int cy = y+dir.getNormal().y; - int cz = z+dir.getNormal().z; - if (!chunk.blockPosInsideChunk(cx, cy, cz)) return true; - IBlockDetailWrapper block = chunk.getBlockDetail(cx, cy, cz); + IBlockDetailWrapper block = chunk.getBlockDetailAtFace(x, y, z, dir); if (block == null || !block.hasFaceCullingFor(LodDirection.OPPOSITE_DIRECTIONS[dir.ordinal()])) return true; } diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java b/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java index 44660c75e..c6dcc5e8d 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java @@ -19,6 +19,8 @@ public class LodQuadBuilder { static final int MAX_QUADS_PER_BUFFER = MAX_BUFFER_SIZE / QUAD_BYTE_SIZE; //static final int MAX_MERGED_QUAD_SIZE = 64; + public boolean skipSkylight0Quads = true; + static class Quad { final short x; final short y; @@ -232,33 +234,40 @@ public class LodQuadBuilder { byte blocklight) { if (dir.ordinal() <= LodDirection.DOWN.ordinal()) throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!"); + if (skipSkylight0Quads && skylight==0) return; quads[dir.ordinal()].add(new Quad(x, y, z, w0, wy, color, skylight, blocklight, dir)); } // XZ public void addQuadUp(short x, short y, short z, short wx, short wz, int color, byte skylight, byte blocklight) { + if (skipSkylight0Quads && skylight==0) return; quads[LodDirection.UP.ordinal()].add(new Quad(x, y, z, wx, wz, color, skylight, blocklight, LodDirection.UP)); } public void addQuadDown(short x, short y, short z, short wx, short wz, int color, byte skylight, byte blocklight) { + if (skipSkylight0Quads && skylight==0) return; quads[LodDirection.DOWN.ordinal()].add(new Quad(x, y, z, wx, wz, color, skylight, blocklight, LodDirection.DOWN)); } // XY public void addQuadN(short x, short y, short z, short wx, short wy, int color, byte skylight, byte blocklight) { + if (skipSkylight0Quads && skylight==0) return; quads[LodDirection.NORTH.ordinal()].add(new Quad(x, y, z, wx, wy, color, skylight, blocklight, LodDirection.NORTH)); } public void addQuadS(short x, short y, short z, short wx, short wy, int color, byte skylight, byte blocklight) { + if (skipSkylight0Quads && skylight==0) return; quads[LodDirection.SOUTH.ordinal()].add(new Quad(x, y, z, wx, wy, color, skylight, blocklight, LodDirection.SOUTH)); } // ZY public void addQuadW(short x, short y, short z, short wz, short wy, int color, byte skylight, byte blocklight) { + if (skipSkylight0Quads && skylight==0) return; quads[LodDirection.WEST.ordinal()].add(new Quad(x, y, z, wz, wy, color, skylight, blocklight, LodDirection.WEST)); } public void addQuadE(short x, short y, short z, short wz, short wy, int color, byte skylight, byte blocklight) { + if (skipSkylight0Quads && skylight==0) return; quads[LodDirection.EAST.ordinal()].add(new Quad(x, y, z, wz, wy, color, skylight, blocklight, LodDirection.EAST)); } diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/chunk/IChunkWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/chunk/IChunkWrapper.java index 85a963c9a..efe6c5c0d 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/chunk/IChunkWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/chunk/IChunkWrapper.java @@ -19,6 +19,7 @@ package com.seibel.lod.core.wrapperInterfaces.chunk; +import com.seibel.lod.core.enums.LodDirection; import com.seibel.lod.core.handlers.dependencyInjection.IBindable; import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; @@ -40,6 +41,9 @@ public interface IChunkWrapper extends IBindable IBiomeWrapper getBiome(int x, int y, int z); IBlockDetailWrapper getBlockDetail(int x, int y, int z); + + // Returns null if block doesn't exist. Note that this can cross chunk boundaries. + IBlockDetailWrapper getBlockDetailAtFace(int x, int y, int z, LodDirection dir); int getChunkPosX(); int getChunkPosZ(); From d2056d824f5cb7aa6b40aa747b8e2de7c06cd8a8 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Mon, 14 Mar 2022 16:22:19 +0800 Subject: [PATCH 06/13] Slight cleanup of lodRenderer --- src/main/java/com/seibel/lod/core/render/LodRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index 8f06d14a6..58b509bc3 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -141,8 +141,8 @@ 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 mcModelViewMatrix This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method - * @param mcProjectionMatrix + * @param baseModelViewMatrix This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method + * @param baseProjectionMatrix * @param partialTicks how far into the current tick this method was called. */ public void drawLODs(LodDimension lodDim, Mat4f baseModelViewMatrix, Mat4f baseProjectionMatrix, float partialTicks, IProfilerWrapper profiler) From 1c0e7839c066ed96754de3f46186a240dd7fcc66 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Tue, 15 Mar 2022 00:00:35 +0800 Subject: [PATCH 07/13] Add Advanced Fog config entries. Actual impl is a todo. --- .../lod/core/enums/rendering/FogSetting.java | 26 +++ .../core/enums/rendering/HeightFogMode.java | 9 + .../config/ILodConfigWrapperSingleton.java | 167 +++++++++++++++++- 3 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java create mode 100644 src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java diff --git a/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java b/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java new file mode 100644 index 000000000..af5281568 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java @@ -0,0 +1,26 @@ +package com.seibel.lod.core.enums.rendering; + +public class FogSetting { + public final double start; + public final double end; + public final double min; + public final double max; + public final double density; + public final Type type; + + public FogSetting(double start, double end, double min, double max, double density, Type type) { + this.start = start; + this.end = end; + this.min = min; + this.max = max; + this.density = density; + this.type = type; + } + + public enum Type { + LINEAR, + EXPONENTIAL, + EXPONENTIAL_SQUARED, + // TEXTURE_BASED, // TODO: Impl this + } +} diff --git a/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java b/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java new file mode 100644 index 000000000..2f7621eb3 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java @@ -0,0 +1,9 @@ +package com.seibel.lod.core.enums.rendering; + +public enum HeightFogMode { + BASIC, + IGNORE_HEIGHT, + ADDITION, + MAX, + SQUARED_ADDITION, +} diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index 8c652f168..de5e845e6 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -31,10 +31,7 @@ import com.seibel.lod.core.enums.config.LightGenerationMode; import com.seibel.lod.core.enums.config.ServerFolderNameMode; import com.seibel.lod.core.enums.config.VanillaOverdraw; import com.seibel.lod.core.enums.config.VerticalQuality; -import com.seibel.lod.core.enums.rendering.DebugMode; -import com.seibel.lod.core.enums.rendering.FogColorMode; -import com.seibel.lod.core.enums.rendering.FogDistance; -import com.seibel.lod.core.enums.rendering.FogDrawMode; +import com.seibel.lod.core.enums.rendering.*; import com.seibel.lod.core.handlers.dependencyInjection.IBindable; import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; import com.seibel.lod.core.objects.MinDefaultMax; @@ -195,7 +192,7 @@ public interface ILodConfigWrapperSingleton extends IBindable + " This setting shouldn't affect performance."; FogDistance getFogDistance(); void setFogDistance(FogDistance newFogDistance); - + FogDrawMode FOG_DRAW_MODE_DEFAULT = FogDrawMode.FOG_ENABLED; String FOG_DRAW_MODE_DESC = "" + " When should fog be drawn? \n" @@ -227,6 +224,166 @@ public interface ILodConfigWrapperSingleton extends IBindable + " Experimental! Mod support is not guarantee."; boolean getDisableVanillaFog(); void setDisableVanillaFog(boolean newDisableVanillaFog); + + IAdvancedFog advancedFog(); + + interface IAdvancedFog { + String DESC = "Advanced settings for fog rendering. Has no effect if Far Fog is not drawn \n" + + "See https://www.desmos.com/calculator/drzzlfmur9 for how setting effect the curve."; + + MinDefaultMax FOG_RANGE = new MinDefaultMax<>(0.0,1.0, Math.sqrt(2.0)); + + MinDefaultMax FAR_FOG_START_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue,0.0, FOG_RANGE.maxValue); + String FAR_FOG_START_DESC = "" + + " Where should the far fog start? \n" + + "\n" + + " '0.0': Fog start at player's position.\n" + + " '1.0': The fog-start's circle fit just in the lod render distance square.\n" + + " '1.414': The lod render distance square fit just in the fog-start's circle.\n"; + double getFarFogStart(); + void setFarFogStart(double newFarFogStart); + + MinDefaultMax FAR_FOG_END_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue,1.0, FOG_RANGE.maxValue); + String FAR_FOG_END_DESC = "" + + " Where should the far fog end? \n" + + "\n" + + " '0.0': Fog end at player's position.\n" + + " '1.0': The fog-end's circle fit just in the lod render distance square.\n" + + " '1.414': The lod render distance square fit just in the fog-end's circle.\n"; + double getFarFogEnd(); + void setFarFogEnd(double newFarFogEnd); + + MinDefaultMax FAR_FOG_MIN_MIN_DEFAULT_MAX = new MinDefaultMax<>(-5.0,0.0, FOG_RANGE.maxValue); + String FAR_FOG_MIN_DESC = "" + + " What is the minimum fog thickness? \n" + + "\n" + + " '0.0': No fog at all.\n" + + " '1.0': Fully fog color.\n"; + double getFarFogMin(); + void setFarFogMin(double newFarFogMin); + + MinDefaultMax FAR_FOG_MAX_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue,1.0, 5.0); + String FAR_FOG_MAX_DESC = "" + + " What is the maximum fog thickness? \n" + + "\n" + + " '0.0': No fog at all.\n" + + " '1.0': Fully fog color.\n"; + double getFarFogMax(); + void setFarFogMax(double newFarFogMax); + + FogSetting.Type FAR_FOG_TYPE_DEFAULT = FogSetting.Type.EXPONENTIAL_SQUARED; + String FAR_FOG_TYPE_DESC = "" + + " How the fog thickness should be calculated from distance? \n" + + "\n" + + " "+ FogSetting.Type.LINEAR + ": Linear based on distance (will ignore 'density')\n" + + " "+ FogSetting.Type.EXPONENTIAL + ": 1/(e^(distance*density)) \n" + + " "+ FogSetting.Type.EXPONENTIAL_SQUARED + ": 1/(e^((distance*density)^2) \n"; + //+ " "+ FogSetting.Type.TEXTURE_BASED + ": Use a provided 1D texture mapping (will ignore 'density', 'min', and 'max')\n"; + FogSetting.Type getFarFogType(); + void setFarFogType(FogSetting.Type newFarFogType); + + MinDefaultMax FAR_FOG_DENSITY_MIN_DEFAULT_MAX = new MinDefaultMax<>(0.01,2.5, 50.0); + String FAR_FOG_DENSITY_DESC = "" + + " What is the fog density? \n"; + double getFarFogDensity(); + void setFarFogDensity(double newFarFogDensity); + + IHeightFog heightFog(); + interface IHeightFog { + String DESC = "Advanced settings for how far fog interacts with height. Has no effect if Far Fog is not drawn \n" + + "See https://www.desmos.com/calculator/drzzlfmur9 for how setting effect the curve."; + + HeightFogMode HEIGHT_FOG_MODE_DEFAULT = HeightFogMode.BASIC; + String HEIGHT_FOG_MODE_DESC = "" + + " How the height should effect the fog thickness combined with the normal function? \n" + + "\n" + + " " + HeightFogMode.BASIC + ": No special height fog effect. Fog is calculated based on camera distance \n" + + " " + HeightFogMode.IGNORE_HEIGHT + ": Ignore height completely. Fog is calculated based on horizontal distance \n" + + " " + HeightFogMode.ADDITION + ": The calculated Height Fog thickness is added to Horizontal Fog thickness \n" + + " " + HeightFogMode.MAX + ": Use the max of Height Fog thickness and Horizontal Fog thickness \n" + + " " + HeightFogMode.SQUARED_ADDITION + ": Height Fog thickness and Horizontal Fog thickness is added via squared scaling \n" + + "\n" + + " Note that for 'BASIC' mode and 'IGNORE_HEIGHT' mode, fog settings for height fog has no effect.\n"; + HeightFogMode getHeightFogMode(); + void setHeightFogType(HeightFogMode newHeightFogMode); + + MinDefaultMax HEIGHT_FOG_START_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue, 0.0, FOG_RANGE.maxValue); + String HEIGHT_FOG_START_DESC = "" + + " Where should the far fog start? \n" + + "\n" + + " '0.0': Fog start at player's position.\n" + + " '1.0': The fog-start's circle fit just in the lod render distance square.\n" + + " '1.414': The lod render distance square fit just in the fog-start's circle.\n"; + double getHeightFogStart(); + void setHeightFogStart(double newHeightFogStart); + + MinDefaultMax HEIGHT_FOG_END_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue, 1.0, FOG_RANGE.maxValue); + String HEIGHT_FOG_END_DESC = "" + + " Where should the far fog end? \n" + + "\n" + + " '0.0': Fog end at player's position.\n" + + " '1.0': The fog-end's circle fit just in the lod render distance square.\n" + + " '1.414': The lod render distance square fit just in the fog-end's circle.\n"; + double getHeightFogEnd(); + void setHeightFogEnd(double newHeightFogEnd); + + MinDefaultMax HEIGHT_FOG_MIN_MIN_DEFAULT_MAX = new MinDefaultMax<>(-5.0, 0.0, FOG_RANGE.maxValue); + String HEIGHT_FOG_MIN_DESC = "" + + " What is the minimum fog thickness? \n" + + "\n" + + " '0.0': No fog at all.\n" + + " '1.0': Fully fog color.\n"; + double getHeightFogMin(); + void setHeightFogMin(double newHeightFogMin); + + MinDefaultMax HEIGHT_FOG_MAX_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue, 1.0, 5.0); + String HEIGHT_FOG_MAX_DESC = "" + + " What is the maximum fog thickness? \n" + + "\n" + + " '0.0': No fog at all.\n" + + " '1.0': Fully fog color.\n"; + double getHeightFogMax(); + void setHeightFogMax(double newHeightFogMax); + + FogSetting.Type HEIGHT_FOG_TYPE_DEFAULT = FogSetting.Type.EXPONENTIAL_SQUARED; + String HEIGHT_FOG_TYPE_DESC = "" + + " How the fog thickness should be calculated from height? \n" + + "\n" + + " " + FogSetting.Type.LINEAR + ": Linear based on height (will ignore 'density')\n" + + " " + FogSetting.Type.EXPONENTIAL + ": 1/(e^(height*density)) \n" + + " " + FogSetting.Type.EXPONENTIAL_SQUARED + ": 1/(e^((height*density)^2) \n"; + //+ " "+ FogSetting.Type.TEXTURE_BASED + ": Use a provided 1D texture mapping (will ignore 'density', 'min', and 'max')\n"; + FogSetting.Type getHeightFogType(); + void setHeightFogType(FogSetting.Type newFarFogType); + + MinDefaultMax HEIGHT_FOG_DENSITY_MIN_DEFAULT_MAX = new MinDefaultMax<>(0.01, 2.5, 50.0); + String HEIGHT_FOG_DENSITY_DESC = "" + + " What is the fog density? \n"; + double getHeightFogDensity(); + void setHeightFogDensity(double newHeightFogDensity); + + default FogSetting computeHeightFogSetting() { + return new FogSetting( + getHeightFogStart(), + getHeightFogEnd(), + getHeightFogMin(), + getHeightFogMax(), + getHeightFogDensity(), + getHeightFogType() + ); + } + } + default FogSetting computeFarFogSetting() { + return new FogSetting( + getFarFogStart(), + getFarFogEnd(), + getFarFogMin(), + getFarFogMax(), + getFarFogDensity(), + getFarFogType() + ); + } + } } /* From 323da0b12c6faf08cf3a02698c0875a6d3242035 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Tue, 15 Mar 2022 12:37:51 +0800 Subject: [PATCH 08/13] Improve GLMessage Parser --- .../com/seibel/lod/core/render/GLProxy.java | 34 +++++++++++++------ .../com/seibel/lod/core/util/GLMessage.java | 23 +++++++++---- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/render/GLProxy.java b/src/main/java/com/seibel/lod/core/render/GLProxy.java index c66d836cb..441a99704 100644 --- a/src/main/java/com/seibel/lod/core/render/GLProxy.java +++ b/src/main/java/com/seibel/lod/core/render/GLProxy.java @@ -62,12 +62,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; */ public class GLProxy { - - - - - - + public static final boolean OVERWIDE_VANILLA_GL_LOGGER = true; private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class); @@ -106,7 +101,8 @@ public class GLProxy public final boolean mapBufferRangeSupported = true; private final GpuUploadMethod preferredUploadMethod; - + + public final GLMessage.Builder vanillaDebugMessageBuilder; public final GLMessage.Builder lodBuilderDebugMessageBuilder; public final GLMessage.Builder proxyWorkerDebugMessageBuilder; @@ -216,7 +212,19 @@ public class GLProxy return true; },null ); - + vanillaDebugMessageBuilder = new GLMessage.Builder( + (type) -> { + if (type == GLMessage.Type.POP_GROUP) return false; + if (type == GLMessage.Type.PUSH_GROUP) return false; + if (type == GLMessage.Type.MARKER) return false; + // if (type == GLMessage.Type.PERFORMANCE) return false; + return true; + } + ,(severity) -> { + if (severity == GLMessage.Severity.NOTIFICATION) return false; + return true; + },null + ); // this must be created on minecraft's render context to work correctly @@ -251,7 +259,12 @@ public class GLProxy MC.crashMinecraft(errorMessage, new UnsupportedOperationException("This GPU doesn't support OpenGL 3.2.")); } ApiShared.LOGGER.info("minecraftGlCapabilities:\n"+getVersionInfo(minecraftGlCapabilities)); - + + if (OVERWIDE_VANILLA_GL_LOGGER) + GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream((msg) -> { + logMessage(msg); + }, vanillaDebugMessageBuilder), true)); + GLFW.glfwMakeContextCurrent(0L); // context creation setup @@ -362,8 +375,7 @@ public class GLProxy // we don't have to change the context, we are already there. if (currentContext == newContext) return; - - + long contextPointer; GLCapabilities newGlCapabilities = null; diff --git a/src/main/java/com/seibel/lod/core/util/GLMessage.java b/src/main/java/com/seibel/lod/core/util/GLMessage.java index 57e7a0b97..93143ea11 100644 --- a/src/main/java/com/seibel/lod/core/util/GLMessage.java +++ b/src/main/java/com/seibel/lod/core/util/GLMessage.java @@ -1,5 +1,6 @@ package com.seibel.lod.core.util; +import com.seibel.lod.core.api.ApiShared; import org.lwjgl.system.CallbackI; import java.util.HashMap; @@ -151,10 +152,14 @@ public final class GLMessage { boolean b = runStage(str); if (b && stage >= 16) { stage = 0; - return new GLMessage(type, severity, source, id, message); - } else { - return null; + GLMessage msg = new GLMessage(type, severity, source, id, message); + if (filterMessage(msg)) { + return msg; + } + } else if (!b) { + ApiShared.LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, stage); } + return null; } public void setTypeFilter(Function typeFilter) { @@ -166,7 +171,14 @@ public final class GLMessage { public void setSourceFilter(Function sourceFilter) { this.sourceFilter = sourceFilter; } - + + private boolean filterMessage(GLMessage msg) { + if (sourceFilter!=null && !sourceFilter.apply(msg.source)) return false; + if (typeFilter!=null && !typeFilter.apply(msg.type)) return false; + if (severityFilter!=null && !severityFilter.apply(msg.severity)) return false; + return true; + } + private boolean runStage(String str) { switch (stage) { case 0: @@ -185,7 +197,6 @@ public final class GLMessage { return checkAndIncStage(str, ":"); case 6: source = Source.get(str); - if (sourceFilter!=null && !sourceFilter.apply(source)) stage = -1; stage++; return true; case 7: @@ -194,7 +205,6 @@ public final class GLMessage { return checkAndIncStage(str, ":"); case 9: type = Type.get(str); - if (typeFilter!=null && !typeFilter.apply(type)) stage = -1; stage++; return true; case 10: @@ -203,7 +213,6 @@ public final class GLMessage { return checkAndIncStage(str, ":"); case 12: severity = Severity.get(str); - if (severityFilter!=null && !severityFilter.apply(severity)) stage = -1; stage++; return true; case 13: From e8de59a226d6d3eb0a062dfb4a86e2a682a6e9c0 Mon Sep 17 00:00:00 2001 From: TomTheFurry Date: Tue, 15 Mar 2022 18:48:27 +1030 Subject: [PATCH 09/13] Fixup MixinUtilBackgroudThread+more render log --- .../core/objects/opengl/LodVertexBuffer.java | 6 +++ .../objects/opengl/SimpleRenderBuffer.java | 9 +++- .../com/seibel/lod/core/render/GLProxy.java | 1 + .../seibel/lod/core/render/LodRenderer.java | 44 ++++++++++++++----- src/main/resources/shaders/flat_shaded.frag | 5 +-- src/main/resources/shaders/standard.vert | 8 +++- 6 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/LodVertexBuffer.java b/src/main/java/com/seibel/lod/core/objects/opengl/LodVertexBuffer.java index 6ff0f1dc1..aa745ca8b 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/LodVertexBuffer.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/LodVertexBuffer.java @@ -199,4 +199,10 @@ public class LodVertexBuffer implements AutoCloseable GL32.glUnmapBuffer(GL32.GL_ARRAY_BUFFER); isMapped = false; } + + @Override + public String toString() { + return (isBufferStorage ? "VertexBufferStorage" : "BufferStorage")+ + "[vboId:"+id+", size:"+size+", vertCount:"+vertexCount+(isMapped?", MAPPED" : "")+"]"; + } } \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java b/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java index 84fafbc58..97ae7cf4d 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java @@ -4,6 +4,8 @@ import java.nio.ByteBuffer; import java.util.Iterator; import java.util.concurrent.TimeUnit; +import com.seibel.lod.core.render.LodRenderer; +import com.seibel.lod.core.util.SpamReducedLogger; import org.lwjgl.opengl.GL32; import com.seibel.lod.core.api.ApiShared; @@ -47,18 +49,21 @@ public class SimpleRenderBuffer extends RenderBuffer // public void onSwapToFront() {} // public void onSwapToBack() {} - + @Override public boolean render(LodRenderProgram shaderProgram) { + boolean hasRendered = false; for (LodVertexBuffer vbo : vbos) { if (vbo == null) continue; if (vbo.vertexCount == 0) continue; + hasRendered = true; GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, vbo.id); shaderProgram.bindVertexBuffer(vbo.id); GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, vbo.vertexCount); + LodRenderer.tickLogger.info("Vertex buffer: {}", vbo); } - return true; + return hasRendered; } @Override diff --git a/src/main/java/com/seibel/lod/core/render/GLProxy.java b/src/main/java/com/seibel/lod/core/render/GLProxy.java index 441a99704..69a30bb6e 100644 --- a/src/main/java/com/seibel/lod/core/render/GLProxy.java +++ b/src/main/java/com/seibel/lod/core/render/GLProxy.java @@ -280,6 +280,7 @@ public class GLProxy GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2); GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE); GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); // create the LodBuilder context lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, minecraftGlContext); diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index 58b509bc3..6a5a7440d 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -24,6 +24,8 @@ import java.time.Duration; import java.util.Set; import java.util.concurrent.TimeUnit; +import com.seibel.lod.core.util.*; +import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL32; import com.seibel.lod.core.api.ApiShared; @@ -39,10 +41,6 @@ import com.seibel.lod.core.objects.math.Vec3d; import com.seibel.lod.core.objects.math.Vec3f; import com.seibel.lod.core.objects.opengl.RenderRegion; import com.seibel.lod.core.render.objects.LightmapTexture; -import com.seibel.lod.core.util.DetailDistanceUtil; -import com.seibel.lod.core.util.LodUtil; -import com.seibel.lod.core.util.MovableGridRingList; -import com.seibel.lod.core.util.MovableGridList; import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; @@ -136,7 +134,22 @@ public class LodRenderer { lodBufferBuilderFactory = newLodNodeBufferBuilder; } - + public static SpamReducedLogger tickLogger = new SpamReducedLogger(1); + + public static void dumpGLState(String str) { + int currentProgram = GL32.glGetInteger(GL32.GL_CURRENT_PROGRAM); + int currentVBO = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING); + int currentVAO = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING); + int currentActiveText = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE); + int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER); + boolean currentBlend = GL32.glGetBoolean(GL32.GL_BLEND); + int currentDepthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC); + tickLogger.info(str + ": [Prog:{}, VAO:{}, VBO:{}, Text:{}, FBO:{}, blend:{}, dpFunc:{}]", + currentProgram, currentVAO, currentVBO, currentActiveText, currentFrameBuffer, + currentBlend, currentDepthFunc); + } + + /** * Besides drawing the LODs this method also starts * the async process of generating the Buffers that hold those LODs. @@ -173,9 +186,13 @@ public class LodRenderer int currentVBO = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING); int currentVAO = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING); int currentActiveText = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE); + int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER); boolean currentBlend = GL32.glGetBoolean(GL32.GL_BLEND); + int currentDepthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC); + dumpGLState("PRE_LOD-DRAW"); + drawSaveGLState.end("drawSaveGLState"); - + GLProxy glProxy = GLProxy.getInstance(); if (canVanillaFogBeDisabled && CONFIG.client().graphics().fogQuality().getDisableVanillaFog()) if (!MC_RENDER.tryDisableVanillaFog()) @@ -253,13 +270,16 @@ public class LodRenderer drawSetPolygon.end("drawSetPolygon"); LagSpikeCatcher drawEnableDepth = new LagSpikeCatcher(); GL32.glEnable(GL32.GL_DEPTH_TEST); - //GL32.glDisable(GL32.GL_DEPTH_TEST); + // GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glDepthFunc(GL32.GL_LEQUAL); drawEnableDepth.end("drawEnableDepth"); drawGLSetup.end("drawGLSetup"); // enable transparent rendering // GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); // GL32.glEnable(GL32.GL_BLEND); - + GL32.glDisable(GL32.GL_BLEND); + // GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT); + /*---------Bind required objects--------*/ // Setup LodRenderProgram and the LightmapTexture if it has not yet been done // also binds LightmapTexture, VAO, and ShaderProgram @@ -315,6 +335,7 @@ public class LodRenderer Vec3d cameraPos = MC_RENDER.getCameraExactPosition(); AbstractBlockPosWrapper cameraBlockPos = MC_RENDER.getCameraBlockPosition(); Vec3f cameraDir = MC_RENDER.getLookAtVector(); + int drawCount = 0; { int ox,oy,dx,dy; @@ -331,8 +352,8 @@ public class LodRenderer { RenderRegion region = regions.get(regionX, regionZ); if (region == null) continue; - region.render(lodDim, cameraPos, cameraBlockPos, cameraDir, - baseModelViewMatrix, !cullingDisabled, shaderProgram); + if (region.render(lodDim, cameraPos, cameraBlockPos, cameraDir, + baseModelViewMatrix, !cullingDisabled, shaderProgram)) drawCount++; } } if( (ox == oy) || ((ox < 0) && (ox == -oy)) || ((ox > 0) && (ox == 1-oy))){ @@ -345,7 +366,7 @@ public class LodRenderer } } //if (drawCall==0) - // ApiShared.LOGGER.info("DrawCall Count: "+drawCall+"("+vCount0+")"); + tickLogger.info("DrawCall Count: {}", drawCount); //================// // render cleanup // @@ -380,6 +401,7 @@ public class LodRenderer drawCleanup.end("LodDrawCleanup"); // end of internal LOD profiling profiler.pop(); + tickLogger.incLogTries(); } //=================// diff --git a/src/main/resources/shaders/flat_shaded.frag b/src/main/resources/shaders/flat_shaded.frag index bea983d82..c9517ed58 100644 --- a/src/main/resources/shaders/flat_shaded.frag +++ b/src/main/resources/shaders/flat_shaded.frag @@ -62,9 +62,8 @@ void main() returnColor = vertexColor; } - - - fragColor = returnColor; + //fragColor = vec4(0.7,0.6,0.5,1.0); + fragColor = vec4(returnColor.rgb,1.0); } diff --git a/src/main/resources/shaders/standard.vert b/src/main/resources/shaders/standard.vert index 9ba0fbdde..6b35cd1ab 100644 --- a/src/main/resources/shaders/standard.vert +++ b/src/main/resources/shaders/standard.vert @@ -30,6 +30,12 @@ void main() vertexColor = color * texture(lightMap, vec2(light,0.5)); vertexWorldPos = worldSpacePos.xyz; - + + // vec4 pos = projectionMatrix * worldSpacePos; gl_Position = projectionMatrix * worldSpacePos; + /*pos.a = 1.0; + if (pos.x>0) pos.x=-1; else pos.x=1; + if (pos.y>0) pos.y=-1; else pos.y=1; + pos.z = 0.5; + gl_Position = pos;*/ } From 4f563c2be5b50c2717a61a4b59045b6ca5d6eb5b Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Tue, 15 Mar 2022 16:38:39 +0800 Subject: [PATCH 10/13] Add proper multi FrameBuffer support(And fix MacOS?) --- .../lod/core/objects/opengl/SimpleRenderBuffer.java | 2 +- .../java/com/seibel/lod/core/render/LodRenderer.java | 12 +++++++----- .../minecraft/IMinecraftRenderWrapper.java | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java b/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java index 97ae7cf4d..b4328d59c 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java @@ -61,7 +61,7 @@ public class SimpleRenderBuffer extends RenderBuffer GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, vbo.id); shaderProgram.bindVertexBuffer(vbo.id); GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, vbo.vertexCount); - LodRenderer.tickLogger.info("Vertex buffer: {}", vbo); + //LodRenderer.tickLogger.info("Vertex buffer: {}", vbo); } return hasRendered; } diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index 6a5a7440d..b125ec8bc 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -25,7 +25,6 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import com.seibel.lod.core.util.*; -import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL32; import com.seibel.lod.core.api.ApiShared; @@ -141,7 +140,7 @@ public class LodRenderer int currentVBO = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING); int currentVAO = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING); int currentActiveText = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE); - int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER); + int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING); boolean currentBlend = GL32.glGetBoolean(GL32.GL_BLEND); int currentDepthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC); tickLogger.info(str + ": [Prog:{}, VAO:{}, VBO:{}, Text:{}, FBO:{}, blend:{}, dpFunc:{}]", @@ -186,7 +185,7 @@ public class LodRenderer int currentVBO = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING); int currentVAO = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING); int currentActiveText = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE); - int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER); + int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING); boolean currentBlend = GL32.glGetBoolean(GL32.GL_BLEND); int currentDepthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC); dumpGLState("PRE_LOD-DRAW"); @@ -253,6 +252,7 @@ public class LodRenderer // Make sure to unbind current VBO so we don't mess up vanilla settings LagSpikeCatcher drawGLSetup = new LagSpikeCatcher(); LagSpikeCatcher drawBindBuff = new LagSpikeCatcher(); + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0); drawBindBuff.end("drawBindBuff"); // set the required open GL settings @@ -271,14 +271,14 @@ public class LodRenderer LagSpikeCatcher drawEnableDepth = new LagSpikeCatcher(); GL32.glEnable(GL32.GL_DEPTH_TEST); // GL32.glDisable(GL32.GL_DEPTH_TEST); - GL32.glDepthFunc(GL32.GL_LEQUAL); + GL32.glDepthFunc(GL32.GL_LESS); drawEnableDepth.end("drawEnableDepth"); drawGLSetup.end("drawGLSetup"); // enable transparent rendering // GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); // GL32.glEnable(GL32.GL_BLEND); GL32.glDisable(GL32.GL_BLEND); - // GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT); + GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT); /*---------Bind required objects--------*/ // Setup LodRenderProgram and the LightmapTexture if it has not yet been done @@ -390,8 +390,10 @@ public class LodRenderer // if this cleanup isn't done MC will crash // when trying to render its own terrain // And may causes mod compat issue + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, currentFrameBuffer); GL32.glUseProgram(currentProgram); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, currentVBO); + GL32.glDepthFunc(currentDepthFunc); GL32.glBindVertexArray(currentVAO); GL32.glActiveTexture(currentActiveText); diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java index 0297909ae..05078c0ac 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java @@ -71,6 +71,8 @@ public interface IMinecraftRenderWrapper extends IBindable int getScreenWidth(); int getScreenHeight(); + + int getTargetFrameBuffer(); /** * This method returns the ChunkPos of all chunks that Minecraft From cf519c02be2c7067bb0f52fd62164a503b3a884a Mon Sep 17 00:00:00 2001 From: TomTheFurry Date: Tue, 15 Mar 2022 21:17:07 +1030 Subject: [PATCH 11/13] Pushed the stuff leetom did on my macbook --- .../java/com/seibel/lod/core/render/LodRenderer.java | 11 +++++++++-- .../minecraft/IMinecraftRenderWrapper.java | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index b125ec8bc..10540bacc 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -143,9 +143,11 @@ public class LodRenderer int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING); boolean currentBlend = GL32.glGetBoolean(GL32.GL_BLEND); int currentDepthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC); - tickLogger.info(str + ": [Prog:{}, VAO:{}, VBO:{}, Text:{}, FBO:{}, blend:{}, dpFunc:{}]", + int[] currentView = new int[4]; + GL32.glGetIntegerv(GL32.GL_VIEWPORT, currentView); + tickLogger.info(str + ": [Prog:{}, VAO:{}, VBO:{}, Text:{}, FBO:{}, blend:{}, dpFunc:{}, view:{}]", currentProgram, currentVAO, currentVBO, currentActiveText, currentFrameBuffer, - currentBlend, currentDepthFunc); + currentBlend, currentDepthFunc, currentView); } @@ -188,6 +190,8 @@ public class LodRenderer int currentFrameBuffer = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING); boolean currentBlend = GL32.glGetBoolean(GL32.GL_BLEND); int currentDepthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC); + int[] currentView = new int[4]; + GL32.glGetIntegerv(GL32.GL_VIEWPORT, currentView); dumpGLState("PRE_LOD-DRAW"); drawSaveGLState.end("drawSaveGLState"); @@ -253,6 +257,7 @@ public class LodRenderer LagSpikeCatcher drawGLSetup = new LagSpikeCatcher(); LagSpikeCatcher drawBindBuff = new LagSpikeCatcher(); GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); + GL32.glViewport(0,0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight()); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0); drawBindBuff.end("drawBindBuff"); // set the required open GL settings @@ -365,6 +370,7 @@ public class LodRenderer oy += dy; } } + dumpGLState("Post Lod Draw Before Cleanup"); //if (drawCall==0) tickLogger.info("DrawCall Count: {}", drawCount); @@ -391,6 +397,7 @@ public class LodRenderer // when trying to render its own terrain // And may causes mod compat issue GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, currentFrameBuffer); + GL32.glViewport(currentView[0], currentView[1],currentView[2],currentView[3]); GL32.glUseProgram(currentProgram); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, currentVBO); GL32.glDepthFunc(currentDepthFunc); diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java index 05078c0ac..7d9fd18ee 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java @@ -73,6 +73,8 @@ public interface IMinecraftRenderWrapper extends IBindable int getScreenHeight(); int getTargetFrameBuffer(); + int getTargetFrameBufferViewportWidth(); + int getTargetFrameBufferViewportHeight(); /** * This method returns the ChunkPos of all chunks that Minecraft From 4097cf76192b7dda96c73d7451ec6dbbb62ec4ef Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Wed, 16 Mar 2022 18:50:41 +0800 Subject: [PATCH 12/13] ADVANCED FOGGGGGGGGGGGGGGGG~~~~~~~~~~~~~~~~ --- .../lod/core/enums/rendering/FogSetting.java | 25 +- .../enums/rendering/HeightFogMixMode.java | 14 + .../core/enums/rendering/HeightFogMode.java | 21 +- .../lod/core/objects/opengl/RenderRegion.java | 15 +- .../seibel/lod/core/render/LodFogConfig.java | 313 +++++++++++++++--- .../lod/core/render/LodRenderProgram.java | 132 ++++---- .../seibel/lod/core/render/LodRenderer.java | 37 ++- .../lod/core/render/objects/Shader.java | 24 +- .../core/render/objects/ShaderProgram.java | 39 ++- .../config/ILodConfigWrapperSingleton.java | 82 +++-- src/main/resources/assets/lod/lang/en_us.json | 106 ++++++ src/main/resources/shaders/flat_shaded.frag | 120 +++---- src/main/resources/shaders/standard.vert | 21 +- 13 files changed, 700 insertions(+), 249 deletions(-) create mode 100644 src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMixMode.java diff --git a/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java b/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java index af5281568..58573cee6 100644 --- a/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java +++ b/src/main/java/com/seibel/lod/core/enums/rendering/FogSetting.java @@ -1,26 +1,43 @@ package com.seibel.lod.core.enums.rendering; +import java.util.Objects; + public class FogSetting { public final double start; public final double end; public final double min; public final double max; public final double density; - public final Type type; + public final FogType fogType; - public FogSetting(double start, double end, double min, double max, double density, Type type) { + public FogSetting(double start, double end, double min, double max, double density, FogType fogType) { this.start = start; this.end = end; this.min = min; this.max = max; this.density = density; - this.type = type; + this.fogType = fogType; } - public enum Type { + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FogSetting that = (FogSetting) o; + return Double.compare(that.start, start) == 0 && Double.compare(that.end, end) == 0 && Double.compare(that.min, min) == 0 && Double.compare(that.max, max) == 0 && Double.compare(that.density, density) == 0 && fogType == that.fogType; + } + + @Override + public int hashCode() { + return Objects.hash(start, end, min, max, density, fogType); + } + + public enum FogType { LINEAR, EXPONENTIAL, EXPONENTIAL_SQUARED, // TEXTURE_BASED, // TODO: Impl this } + + } diff --git a/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMixMode.java b/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMixMode.java new file mode 100644 index 000000000..7ee8ceadc --- /dev/null +++ b/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMixMode.java @@ -0,0 +1,14 @@ +package com.seibel.lod.core.enums.rendering; + +public enum HeightFogMixMode { + BASIC, + IGNORE_HEIGHT, + ADDITION, + MAX, + MULTIPLY, + INVERSE_MULTIPLY, + LIMITED_ADDITION, + MULTIPLY_ADDITION, + INVERSE_MULTIPLY_ADDITION, + AVERAGE, +} diff --git a/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java b/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java index 2f7621eb3..87542199f 100644 --- a/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java +++ b/src/main/java/com/seibel/lod/core/enums/rendering/HeightFogMode.java @@ -1,9 +1,20 @@ package com.seibel.lod.core.enums.rendering; public enum HeightFogMode { - BASIC, - IGNORE_HEIGHT, - ADDITION, - MAX, - SQUARED_ADDITION, + ABOVE_CAMERA(true, true, false), + BELOW_CAMERA(true, false, true), + ABOVE_AND_BELOW_CAMERA(true, true, true), + ABOVE_SET_HEIGHT(false, true, false), + BELOW_SET_HEIGHT(false, false, true), + ABOVE_AND_BELOW_SET_HEIGHT(false, true, true); + + public final boolean basedOnCamera; + public final boolean above; + public final boolean below; + + HeightFogMode(boolean basedOnCamera, boolean above, boolean below) { + this.basedOnCamera = basedOnCamera; + this.above = above; + this.below = below; + } } diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java b/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java index 85291081e..ad2816ecd 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java @@ -109,7 +109,7 @@ public class RenderRegion implements AutoCloseable public boolean render(LodDimension renderDim, Vec3d cameraPos, AbstractBlockPosWrapper cameraBlockPos, Vec3f cameraDir, - Mat4f baseModelViewMatrix, boolean enableDirectionalCulling, LodRenderProgram program) { + boolean enableDirectionalCulling, LodRenderProgram program) { if (!frontState.compareAndSet(FrontState.Unused, FrontState.Rendering)) return false; try { if (renderDim != lodDim) return false; @@ -120,7 +120,7 @@ public class RenderRegion implements AutoCloseable if (state == BackState.Complete) { if (renderBufferBack != null) { if (ENABLE_EVENT_LOGGING) ApiShared.LOGGER.info("RenderRegion swap @ {}", regionPos); - boolean shouldKeep = renderBufferFront==null ? false : renderBufferFront.onSwapToBack(); + boolean shouldKeep = renderBufferFront != null && renderBufferFront.onSwapToBack(); RenderBuffer temp = shouldKeep ? renderBufferFront : null; renderBufferFront = renderBufferBack; renderBufferBack = temp; @@ -131,12 +131,11 @@ public class RenderRegion implements AutoCloseable } } if (renderBufferFront == null) return false; - Mat4f localModelViewMatrix = baseModelViewMatrix.copy(); - localModelViewMatrix.multiplyTranslationMatrix( - (regionPos.x * LodUtil.REGION_WIDTH) - cameraPos.x, - LodBuilder.MIN_WORLD_HEIGHT - cameraPos.y, - (regionPos.z * LodUtil.REGION_WIDTH) - cameraPos.z); - program.fillUniformModelMatrix(localModelViewMatrix); + program.setModelPos(new Vec3f( + (float) ((regionPos.x * LodUtil.REGION_WIDTH) - cameraPos.x), + (float) (LodBuilder.MIN_WORLD_HEIGHT - cameraPos.y), + (float) ((regionPos.z * LodUtil.REGION_WIDTH) - cameraPos.z))); + return renderBufferFront.render(program); } finally { frontState.compareAndSet(FrontState.Rendering, FrontState.Unused); diff --git a/src/main/java/com/seibel/lod/core/render/LodFogConfig.java b/src/main/java/com/seibel/lod/core/render/LodFogConfig.java index 7c2d2abe1..b65ac0d28 100644 --- a/src/main/java/com/seibel/lod/core/render/LodFogConfig.java +++ b/src/main/java/com/seibel/lod/core/render/LodFogConfig.java @@ -19,11 +19,18 @@ package com.seibel.lod.core.render; -import com.seibel.lod.core.enums.rendering.FogDistance; -import com.seibel.lod.core.enums.rendering.FogDrawMode; +import com.seibel.lod.core.api.ApiShared; +import com.seibel.lod.core.enums.rendering.*; import com.seibel.lod.core.handlers.IReflectionHandler; +import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; +import com.seibel.lod.core.render.objects.Shader; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + /** * This object is just a replacement for an array * to make things easier to understand in the LodRenderer. @@ -33,43 +40,269 @@ import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; */ public class LodFogConfig { - public FogDrawMode fogDrawMode; - public FogDistance fogDistance; - - public float nearFogStart = 0; - public float nearFogEnd = 0; - - public float farFogStart = 0; - public float farFogEnd = 0; - - public LodFogConfig(ILodConfigWrapperSingleton config, IReflectionHandler reflectionHandler, int farPlaneBlockDistance, int vanillaBlockRenderedDistance) { - - fogDrawMode = config.client().graphics().fogQuality().getFogDrawMode(); - if (fogDrawMode == FogDrawMode.USE_OPTIFINE_SETTING) - fogDrawMode = reflectionHandler.getFogDrawMode(); - - // how different distances are drawn depends on the quality set - fogDistance = config.client().graphics().fogQuality().getFogDistance(); - - // far fog // - - if (config.client().graphics().fogQuality().getFogDistance() == FogDistance.NEAR_AND_FAR) - farFogStart = farPlaneBlockDistance * 0.9f; - else - // for more realistic fog when using FAR - farFogStart = Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f); - - farFogEnd = farPlaneBlockDistance; - - - // near fog // - - // the reason that I wrote fogEnd then fogStart backwards - // is because we are using fog backwards to how - // it is normally used, hiding near objects - // instead of far objects. - nearFogEnd = vanillaBlockRenderedDistance * 1.41f; - nearFogStart = vanillaBlockRenderedDistance * 1.6f; + private static final IReflectionHandler REFLECTION_HANDLER = SingletonHandler.get(IReflectionHandler.class); + private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); + + public static final boolean DEBUG_DUMP_GENERATED_CODE = true; + + public final FogSetting farFogSetting; + public final FogSetting heightFogSetting; + public final HeightFogMixMode heightFogMixMode; + public final HeightFogMode heightFogMode; + public final float heightFogHeight; + + final boolean drawNearFog; + + public static LodFogConfig generateFogConfig() { + FogDrawMode doDraw = CONFIG.client().graphics().fogQuality().getFogDrawMode(); + if (doDraw == FogDrawMode.USE_OPTIFINE_SETTING) + doDraw = REFLECTION_HANDLER.getFogDrawMode(); + return new LodFogConfig(doDraw); + } + + private LodFogConfig(FogDrawMode fogDrawMode) { + if (fogDrawMode == FogDrawMode.FOG_DISABLED) { + drawNearFog = false; + farFogSetting = null; + heightFogMixMode = null; + heightFogMode = null; + heightFogSetting = null; + heightFogHeight = 0.f; + } else { + ILodConfigWrapperSingleton.IClient.IGraphics.IFogQuality setting = CONFIG.client().graphics().fogQuality(); + FogDistance fogDistance = setting.getFogDistance(); + drawNearFog = (fogDistance == FogDistance.NEAR || fogDistance == FogDistance.NEAR_AND_FAR); + if (fogDistance == FogDistance.FAR || fogDistance == FogDistance.NEAR_AND_FAR) { + farFogSetting = setting.advancedFog().computeFarFogSetting(); + heightFogMixMode = setting.advancedFog().heightFog().getHeightFogMixMode(); + if (heightFogMixMode != HeightFogMixMode.IGNORE_HEIGHT && heightFogMixMode != HeightFogMixMode.BASIC) { + heightFogSetting = setting.advancedFog().heightFog().computeHeightFogSetting(); + heightFogMode = setting.advancedFog().heightFog().getHeightFogMode(); + if (heightFogMode.basedOnCamera) { + heightFogHeight = 0.f; + } else { + heightFogHeight = (float) setting.advancedFog().heightFog().getHeightFogHeight(); + } + } else { + heightFogSetting = null; + heightFogMode = null; + heightFogHeight = 0.f; + } + } else { + farFogSetting = null; + heightFogSetting = null; + heightFogMode = null; + heightFogMixMode = null; + heightFogHeight = 0.f; + } + } + } + + public StringBuilder loadAndProcessFragShader(String path, boolean absoluteFilePath) { + StringBuilder str = makeRuntimeDefine(); + generateRuntimeShaderCode(Shader.loadFile(path, absoluteFilePath, str)); + if (DEBUG_DUMP_GENERATED_CODE) { + try (FileOutputStream file = new FileOutputStream("debugGenerated.frag", false)) { + file.write(str.toString().getBytes(StandardCharsets.UTF_8)); + ApiShared.LOGGER.info("Debug dumped generated code to debugGenerated.frag for {}", path); + } catch (IOException e) { + ApiShared.LOGGER.warn("Failed to debug dump generated code to file for {}", path); + } + } + return str; + } + + private StringBuilder makeRuntimeDefine() { + StringBuilder str = new StringBuilder(); + str.append("// =======RUNTIME GENERATED DEFINE SECTION========\n#version 150 core\n"); + + if (farFogSetting == null) { + str.append(""" +#define farFogStart 0.0 +#define farFogLength 0.0 +#define farFogMin 0.0 +#define farFogRange 0.0 +#define farFogDensity 0.0 +#define heightFogStart 0.0 +#define heightFogLength 0.0 +#define heightFogMin 0.0 +#define heightFogRange 0.0 +#define heightFogDensity 0.0 + """); + } else { + str.append("\n#define farFogStart "); + str.append(farFogSetting.start); + str.append("\n#define farFogLength "); + str.append(farFogSetting.end - farFogSetting.start); + str.append("\n#define farFogMin "); + str.append(farFogSetting.min); + str.append("\n#define farFogRange "); + str.append(farFogSetting.max - farFogSetting.min); + str.append("\n#define farFogDensity "); + str.append(farFogSetting.density); + str.append("\n"); + + if (heightFogSetting == null) { + str.append(""" +#define heightFogStart 0.0 +#define heightFogLength 0.0 +#define heightFogMin 0.0 +#define heightFogRange 0.0 +#define heightFogDensity 0.0 + """); + } else { + str.append("\n#define heightFogStart "); + str.append(heightFogSetting.start); + str.append("\n#define heightFogLength "); + str.append(heightFogSetting.end - heightFogSetting.start); + str.append("\n#define heightFogMin "); + str.append(heightFogSetting.min); + str.append("\n#define heightFogRange "); + str.append(heightFogSetting.max - heightFogSetting.min); + str.append("\n#define heightFogDensity "); + str.append(heightFogSetting.density); + str.append("\n"); + } + } + str.append("// =======RUNTIME END========\n"); + return str; + } + + private static String getFarFogMethod(FogSetting.FogType fogType) { + switch (fogType) { + case LINEAR: + return " return linearFog(dist, farFogStart, farFogLength, farFogMin, farFogRange);\n"; + case EXPONENTIAL: + return " return exponentialFog(dist, farFogStart, farFogLength, farFogMin, farFogRange, farFogDensity);\n"; + case EXPONENTIAL_SQUARED: + return " return exponentialSquaredFog(dist, farFogStart, farFogLength, farFogMin, farFogRange, farFogDensity);\n"; + } + throw new IllegalArgumentException(); + } + private static String getHeightDepthMethod(HeightFogMode mode, float heightFogHeight) { + String str = ""; + if (!mode.basedOnCamera) { + str = " vertical = realY - (" + heightFogHeight + ");\n"; + } + if (mode.below && mode.above) { + str += " return abs(vertical);\n"; + } else if (mode.below) { + str += " return -vertical;\n"; + } else if (mode.above) { + str += " return vertical;\n"; + } else { + str += " return 0;\n"; + } + return str; + } + + private static String getHeightFogMethod(FogSetting.FogType fogType) { + switch (fogType) { + case LINEAR: + return " return linearFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange);\n"; + case EXPONENTIAL: + return " return exponentialFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange, heightFogDensity);\n"; + case EXPONENTIAL_SQUARED: + return " return exponentialSquaredFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange, heightFogDensity);\n"; + } + throw new IllegalArgumentException(); + } + private static String getMixFogMethod(HeightFogMixMode mode) { + switch (mode) { + case BASIC: + case IGNORE_HEIGHT: + return " return max(near, far);\n"; + case ADDITION: + return " return max(near, far + height);\n"; + case MAX: + return " return max(near, max(far, height));\n"; + case INVERSE_MULTIPLY: + return " return max(near, 1.0 - (1.0-far)*(1.0-height));\n"; + case MULTIPLY: + return " return max(near, far*height);\n"; + case LIMITED_ADDITION: + return " return max(near, far + max(far, height));\n"; + case MULTIPLY_ADDITION: + return " return max(near, far + far*height);\n"; + case INVERSE_MULTIPLY_ADDITION: + return " return max(near, far + 1.0 - (1.0-far)*(1.0-height));\n"; + case AVERAGE: + return " return max(near, far*0.5 + height*0.5);\n"; + } + throw new IllegalArgumentException(); + } + + private void generateRuntimeShaderCode(StringBuilder str) { + str.append("// =======RUNTIME GENERATED CODE SECTION========\n"); + + // Generate method: float getNearFogThickness(float dist); + if (drawNearFog) { + str.append(""" +float getNearFogThickness(float dist) { + return linearFog(dist, nearFogStart, nearFogLength, 1.0, -1.0); +} + """); + } else { + str.append(""" +float getNearFogThickness(float dist) {return 0.0;} + """); + } + + if (farFogSetting == null) { + str.append(""" +float getFarFogThickness(float dist) { return 0.0; } +float getHeightFogThickness(float dist) { return 0.0; } +float calculateFarFogDepth(float horizontal, float dist) { return 0.0; } +float calculateHeightFogDepth(float vertical, float realY) { return 0.0; } +float mixFogThickness(float near, float far, float height) { return near; } + """); + } else { + // Generate method: float getFarFogThickness(float dist); + str.append("float getFarFogThickness(float dist) {\n"); + str.append(getFarFogMethod(farFogSetting.fogType)); + str.append("}\n"); + + // Generate method: float getHeightFogThickness(float dist); + if (heightFogSetting == null) { + str.append(""" +float getHeightFogThickness(float dist) { return 0.0; } +float calculateHeightFogDepth(float vertical, float realY) { return 0.0; } + """); + } else { + str.append("float getHeightFogThickness(float dist) {\n"); + str.append(getHeightFogMethod(heightFogSetting.fogType)); + str.append("}\n"); + str.append("float calculateHeightFogDepth(float vertical, float realY) {\n"); + str.append(getHeightDepthMethod(heightFogMode, heightFogHeight)); + str.append("}\n"); + } + + // Generate method: calculateFarFogDepth(float horizontal, float vertical, float dist); + str.append("float calculateFarFogDepth(float horizontal, float dist) {\n"); + if (heightFogMixMode == HeightFogMixMode.BASIC) { + str.append(" return dist;\n"); + } else { + str.append(" return horizontal;\n"); + } + str.append("}\n"); + + // Generate method: float mixFogThickness(float near, float far, float height); + str.append("float mixFogThickness(float near, float far, float height) {\n"); + str.append(getMixFogMethod(heightFogMixMode)); + str.append("}\n"); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LodFogConfig that = (LodFogConfig) o; + return Float.compare(that.heightFogHeight, heightFogHeight) == 0 && drawNearFog == that.drawNearFog && Objects.equals(farFogSetting, that.farFogSetting) && Objects.equals(heightFogSetting, that.heightFogSetting) && heightFogMixMode == that.heightFogMixMode && heightFogMode == that.heightFogMode; + } + + @Override + public int hashCode() { + return Objects.hash(farFogSetting, heightFogSetting, heightFogMixMode, heightFogMode, heightFogHeight, drawNearFog); } - } diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java b/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java index 977cdb38a..63159e6c6 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java @@ -23,65 +23,66 @@ import java.awt.Color; import com.seibel.lod.core.enums.rendering.FogDistance; import com.seibel.lod.core.enums.rendering.FogDrawMode; +import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; import com.seibel.lod.core.objects.math.Mat4f; -import com.seibel.lod.core.render.objects.ShaderProgram; -import com.seibel.lod.core.render.objects.VertexAttribute; -import com.seibel.lod.core.render.objects.VertexAttributePostGL43; -import com.seibel.lod.core.render.objects.VertexAttributePreGL43; +import com.seibel.lod.core.objects.math.Vec3f; +import com.seibel.lod.core.render.objects.*; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.wrapperInterfaces.IVersionConstants; +import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; public class LodRenderProgram extends ShaderProgram { public static final String VERTEX_SHADER_PATH = "shaders/standard.vert"; public static final String FRAGMENT_SHADER_PATH = "shaders/flat_shaded.frag"; + private static final IVersionConstants VERSION_CONSTANTS = SingletonHandler.get(IVersionConstants.class); public final VertexAttribute vao; // Attributes public final int posAttrib; public final int colAttrib; - //public final int lightAttrib; //Sky light then block light + // Uniforms - public final int mvmUniform; - public final int projUniform; - //public final int cameraUniform; - public final int fogColorUniform; - // public final int skyLightUniform; worldSkyLight is currently not used + public final int combinedMatUniform; + public final int modelOffsetUniform; + public final int worldYOffsetUniform; + public final int lightMapUniform; // Fog Uniforms - public final int fogEnabledUniform; - public final int nearFogEnabledUniform; - public final int farFogEnabledUniform; + public final int fogColorUniform; + public final int fogScaleUniform; + public final int fogVerticalScaleUniform; public final int nearFogStartUniform; - public final int nearFogEndUniform; - public final int farFogStartUniform; - public final int farFogEndUniform; + public final int nearFogLengthUniform;; + public final int fullFogModeUniform; + + public final LodFogConfig fogConfig; // This will bind VertexAttribute - public LodRenderProgram() { - super(VERTEX_SHADER_PATH, FRAGMENT_SHADER_PATH, "fragColor"); + public LodRenderProgram(LodFogConfig fogConfig) { + super(() -> Shader.loadFile(VERTEX_SHADER_PATH, false, new StringBuilder()).toString(), + () -> fogConfig.loadAndProcessFragShader(FRAGMENT_SHADER_PATH, false).toString(), + "fragColor"); + this.fogConfig = fogConfig; posAttrib = getAttributeLocation("vPosition"); - colAttrib = getAttributeLocation("color"); - //lightAttrib = getAttributeLocation("light"); - - mvmUniform = getUniformLocation("modelViewMatrix"); - projUniform = getUniformLocation("projectionMatrix"); - //cameraUniform = getUniformLocation("cameraPos"); - fogColorUniform = getUniformLocation("fogColor"); - // skyLightUniform = getUniformLocation("worldSkyLight"); + colAttrib = tryGetAttributeLocation("color"); // might be optimized out in some fog settings + + combinedMatUniform = getUniformLocation("combinedMatrix"); + modelOffsetUniform = getUniformLocation("modelOffset"); + worldYOffsetUniform = tryGetUniformLocation("worldYOffset"); + lightMapUniform = getUniformLocation("lightMap"); // Fog uniforms - fogEnabledUniform = getUniformLocation("fogEnabled"); - nearFogEnabledUniform = getUniformLocation("nearFogEnabled"); - farFogEnabledUniform = getUniformLocation("farFogEnabled"); + fullFogModeUniform = getUniformLocation("fullFogMode"); + fogColorUniform = getUniformLocation("fogColor"); + fogScaleUniform = tryGetUniformLocation("fogScale"); + fogVerticalScaleUniform = tryGetUniformLocation("fogVerticalScale"); // near - nearFogStartUniform = getUniformLocation("nearFogStart"); - nearFogEndUniform = getUniformLocation("nearFogEnd"); - // far - farFogStartUniform = getUniformLocation("farFogStart"); - farFogEndUniform = getUniformLocation("farFogEnd"); - + nearFogStartUniform = tryGetUniformLocation("nearFogStart"); + nearFogLengthUniform = tryGetUniformLocation("nearFogLength"); + // TODO: Add better use of the LODFormat thing int vertexByteCount = LodUtil.LOD_VERTEX_FORMAT.getByteSize(); if (GLProxy.getInstance().VertexAttributeBufferBindingSupported) @@ -92,7 +93,7 @@ public class LodRenderProgram extends ShaderProgram { // Now a pos+light. vao.setVertexAttribute(0, posAttrib, VertexAttribute.VertexPointer.addUnsignedShortsPointer(4, false)); // 2+2+2+2 //vao.setVertexAttribute(0, posAttrib, VertexAttribute.VertexPointer.addVec3Pointer(false)); // 4+4+4 - vao.setVertexAttribute(0, colAttrib, VertexAttribute.VertexPointer.addUnsignedBytesPointer(4, true)); // +4 + vao.setVertexAttribute(0, colAttrib == -1 ? 2 : colAttrib, VertexAttribute.VertexPointer.addUnsignedBytesPointer(4, true)); // +4 //vao.setVertexAttribute(0, lightAttrib, VertexAttribute.VertexPointer.addUnsignedBytesPointer(2, false)); // +4 due to how it aligns try { vao.completeAndCheck(vertexByteCount); @@ -101,6 +102,13 @@ public class LodRenderProgram extends ShaderProgram { throw e; } } + + // If not usable, return a new LodFogConfig to be constructed + public LodFogConfig isShaderUsable() { + LodFogConfig newConfig = LodFogConfig.generateFogConfig(); + if (fogConfig.equals(newConfig)) return null; + return newConfig; + } // Override ShaderProgram.bind() public void bind() { @@ -127,41 +135,33 @@ public class LodRenderProgram extends ShaderProgram { vao.unbindBuffersFromAllBindingPoint(); } - public void fillUniformData(Mat4f projectionMatrix, Color fogColor, int skyLight, int lightmapBindPoint) { + public void fillUniformData(Mat4f combinedMatrix, Color fogColor, + int lightmapBindPoint, int worldHeight, int worldYOffset, int lodDrawDistance, + int vanillaDrawDistance, boolean fullFogMode) { super.bind(); + vanillaDrawDistance += 32; // Give it a 2 chunk boundary for near fog. // uniforms - setUniform(projUniform, projectionMatrix); - setUniform(fogColorUniform, fogColor); + setUniform(combinedMatUniform, combinedMatrix); + // setUniform(skyLightUniform, skyLight); setUniform(lightMapUniform, lightmapBindPoint); + + if (worldYOffsetUniform != -1) setUniform(worldYOffsetUniform, (float)worldYOffset); + + // Fog + setUniform(fullFogModeUniform, fullFogMode ? 1 : 0); + setUniform(fogColorUniform, fogColor); + + float nearFogLen = vanillaDrawDistance * 0.2f / lodDrawDistance; + float nearFogStart = vanillaDrawDistance * (VERSION_CONSTANTS.isVanillaRenderedChunkSquare() ? (float)Math.sqrt(2.) : 1.f) / lodDrawDistance; + if (nearFogStartUniform != -1) setUniform(nearFogStartUniform, nearFogStart); + if (nearFogLengthUniform != -1) setUniform(nearFogLengthUniform, nearFogLen); + if (fogScaleUniform != -1) setUniform(fogScaleUniform, 1.f/lodDrawDistance); + if (fogVerticalScaleUniform != -1) setUniform(fogVerticalScaleUniform, 1.f/worldHeight); } - - public void fillUniformModelMatrix(Mat4f modelViewMatrix) { - super.bind(); - setUniform(mvmUniform, modelViewMatrix); - } - - public void fillUniformDataForFog(LodFogConfig fogSettings, boolean allFogMode) { - super.bind(); - if (allFogMode) { - setUniform(fogEnabledUniform, true); - setUniform(nearFogEnabledUniform, false); - setUniform(farFogEnabledUniform, true); - setUniform(farFogStartUniform, 0.0f); - setUniform(farFogEndUniform, 0.0f); - } else if (fogSettings.fogDrawMode != FogDrawMode.FOG_DISABLED) { - setUniform(fogEnabledUniform, true); - setUniform(nearFogEnabledUniform, fogSettings.fogDistance != FogDistance.FAR); - setUniform(farFogEnabledUniform, fogSettings.fogDistance != FogDistance.NEAR); - // near - setUniform(nearFogStartUniform, fogSettings.nearFogStart); - setUniform(nearFogEndUniform, fogSettings.nearFogEnd); - // far - setUniform(farFogStartUniform, fogSettings.farFogStart); - setUniform(farFogEndUniform, fogSettings.farFogEnd); - } else { - setUniform(fogEnabledUniform, false); - } + + public void setModelPos(Vec3f modelPos) { + setUniform(modelOffsetUniform, modelPos); } } diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index 10540bacc..0c3efefe6 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -77,7 +77,6 @@ public class LodRenderer private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.get(IMinecraftRenderWrapper.class); private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); - private static final IReflectionHandler REFLECTION_HANDLER = SingletonHandler.get(IReflectionHandler.class); public static final int VANILLA_REFRESH_TIMEOUT = 60; /** @@ -251,7 +250,6 @@ public class LodRenderer profiler.push("LOD draw setup"); LagSpikeCatcher drawSetup = new LagSpikeCatcher(); - /*---------Set GL State--------*/ // Make sure to unbind current VBO so we don't mess up vanilla settings LagSpikeCatcher drawGLSetup = new LagSpikeCatcher(); @@ -294,6 +292,11 @@ public class LodRenderer drawObjectSetup.end("drawObjectSetup"); } else { LagSpikeCatcher drawShaderBind = new LagSpikeCatcher(); + LodFogConfig newConfig = shaderProgram.isShaderUsable(); + if (newConfig != null) { + shaderProgram.free(); + shaderProgram = new LodRenderProgram(newConfig); + } shaderProgram.bind(); drawShaderBind.end("drawShaderBind"); } @@ -312,18 +315,18 @@ public class LodRenderer farPlaneBlockDistance = Math.min(CONFIG.client().graphics().quality().getLodChunkRenderDistance(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * LodUtil.CHUNK_WIDTH; else farPlaneBlockDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * LodUtil.CHUNK_WIDTH; - LodFogConfig fogSettings = new LodFogConfig(CONFIG, REFLECTION_HANDLER, farPlaneBlockDistance, vanillaBlockRenderedDistance); drawCalculateParams.end("drawCalculateParams"); - Mat4f projectionMatrix = createProjectionMatrix(baseProjectionMatrix, vanillaBlockRenderedDistance, farPlaneBlockDistance); + + Mat4f combinedMatrix = createCombinedMatrix(baseProjectionMatrix, baseModelViewMatrix, vanillaBlockRenderedDistance, farPlaneBlockDistance); /*---------Fill uniform data--------*/ LagSpikeCatcher drawFillData = new LagSpikeCatcher(); // Fill the uniform data. Note: GL33.GL_TEXTURE0 == texture bindpoint 0 - shaderProgram.fillUniformData(projectionMatrix, + shaderProgram.fillUniformData(combinedMatrix, MC_RENDER.isFogStateSpecial() ? getSpecialFogColor(partialTicks) : getFogColor(partialTicks), - (int) (MC.getSkyDarken(partialTicks) * 15), 0); - // Previous guy said fog setting may be different from region to region, but the fogSettings never changed... soooooo... - shaderProgram.fillUniformDataForFog(fogSettings, MC_RENDER.isFogStateSpecial()); + 0, MC.getWrappedClientWorld().getHeight(), MC.getWrappedClientWorld().getMinHeight(), farPlaneBlockDistance, + vanillaBlockRenderedDistance, MC_RENDER.isFogStateSpecial()); + // Note: Since lightmapTexture is changing every frame, it's faster to recreate it than to reuse the old one. LagSpikeCatcher drawFillLightmap = new LagSpikeCatcher(); lightmapTexture.fillData(MC_RENDER.getLightmapTextureWidth(), MC_RENDER.getLightmapTextureHeight(), MC_RENDER.getLightmapPixels()); @@ -358,7 +361,7 @@ public class LodRenderer RenderRegion region = regions.get(regionX, regionZ); if (region == null) continue; if (region.render(lodDim, cameraPos, cameraBlockPos, cameraDir, - baseModelViewMatrix, !cullingDisabled, shaderProgram)) drawCount++; + !cullingDisabled, shaderProgram)) drawCount++; } } if( (ox == oy) || ((ox < 0) && (ox == -oy)) || ((ox > 0) && (ox == 1-oy))){ @@ -429,7 +432,7 @@ public class LodRenderer } isSetupComplete = true; - shaderProgram = new LodRenderProgram(); + shaderProgram = new LodRenderProgram(LodFogConfig.generateFogConfig()); } /** Create all buffers that will be used. */ @@ -456,18 +459,22 @@ public class LodRenderer /** * create and return a new projection matrix based on MC's projection matrix - * @param currentProjectionMatrix this is Minecraft's current projection matrix + * @param projMat this is Minecraft's current projection matrix + * @param modelMat this is Minecraft's current model matrix * @param vanillaBlockRenderedDistance Minecraft's vanilla far plane distance */ - private static Mat4f createProjectionMatrix(Mat4f currentProjectionMatrix, float vanillaBlockRenderedDistance, int farPlaneBlockDistance) + private static Mat4f createCombinedMatrix(Mat4f projMat, Mat4f modelMat, float vanillaBlockRenderedDistance, int farPlaneBlockDistance) { //Create a copy of the current matrix, so the current matrix isn't modified. - Mat4f lodProj = currentProjectionMatrix.copy(); + Mat4f lodProj = projMat.copy(); //Set new far and near clip plane values. lodProj.setClipPlanes( - CONFIG.client().graphics().advancedGraphics().getUseExtendedNearClipPlane() ? vanillaBlockRenderedDistance / 5 : 1, - farPlaneBlockDistance * LodUtil.CHUNK_WIDTH / 2); + CONFIG.client().graphics().advancedGraphics().getUseExtendedNearClipPlane() ? + (vanillaBlockRenderedDistance-16) : 16, + (float)((farPlaneBlockDistance+LodUtil.REGION_WIDTH) * Math.sqrt(2))); + + lodProj.multiply(modelMat); return lodProj; } diff --git a/src/main/java/com/seibel/lod/core/render/objects/Shader.java b/src/main/java/com/seibel/lod/core/render/objects/Shader.java index f2fe0469e..9deaa8786 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/Shader.java +++ b/src/main/java/com/seibel/lod/core/render/objects/Shader.java @@ -54,7 +54,7 @@ public class Shader ApiShared.LOGGER.info("Loading shader at "+path); // Create an empty shader object id = GL32.glCreateShader(type); - StringBuilder source = loadFile(path, absoluteFilePath); + StringBuilder source = loadFile(path, absoluteFilePath, new StringBuilder()); GL32.glShaderSource(id, source); GL32.glCompileShader(id); @@ -68,14 +68,30 @@ public class Shader ApiShared.LOGGER.info("Shader at "+path+" loaded sucessfully."); } + public Shader(int type, String sourceString) + { + ApiShared.LOGGER.info("Loading shader with soruceString:\n{}", sourceString); + // Create an empty shader object + id = GL32.glCreateShader(type); + GL32.glShaderSource(id, sourceString); + + GL32.glCompileShader(id); + // check if the shader compiled + int status = GL32.glGetShaderi(id, GL32.GL_COMPILE_STATUS); + if (status != GL32.GL_TRUE) { + String message = "Shader compiler error. Details: "+GL32.glGetShaderInfoLog(id); + free(); // important! + throw new RuntimeException(message); + } + ApiShared.LOGGER.info("Shader loaded sucessfully."); + } + // REMEMBER to always free the resource! public void free() { GL32.glDeleteShader(id); } - private StringBuilder loadFile(String path, boolean absoluteFilePath) { - StringBuilder stringBuilder = new StringBuilder(); - + public static StringBuilder loadFile(String path, boolean absoluteFilePath, StringBuilder stringBuilder) { try { // open the file diff --git a/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java b/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java index 31db6214c..fe34d16c5 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java +++ b/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java @@ -21,6 +21,7 @@ package com.seibel.lod.core.render.objects; import java.awt.Color; import java.nio.FloatBuffer; +import java.util.function.Supplier; import org.lwjgl.opengl.GL32; import org.lwjgl.system.MemoryStack; @@ -49,19 +50,26 @@ public class ShaderProgram * This will bind ShaderProgram */ public ShaderProgram(String vert, String frag, String fragDataOutputName) { - Shader vertShader = new Shader(GL32.GL_VERTEX_SHADER, vert, false); - Shader fragShader = new Shader(GL32.GL_FRAGMENT_SHADER, frag, false); - + this(() -> Shader.loadFile(vert, false, new StringBuilder()).toString(), + () -> Shader.loadFile(frag, false, new StringBuilder()).toString(), + fragDataOutputName); + } + + public ShaderProgram(Supplier vert, Supplier frag, String fragDataOutputName) + { + Shader vertShader = new Shader(GL32.GL_VERTEX_SHADER, vert.get()); + Shader fragShader = new Shader(GL32.GL_FRAGMENT_SHADER, frag.get()); + id = GL32.glCreateProgram(); - + GL32.glAttachShader(this.id, vertShader.id); GL32.glAttachShader(this.id, fragShader.id); - //GL32.glBindFragDataLocation(id, 0, fragDataOutputName); + //GL32.glBindFragDataLocation(id, 0, fragDataOutputName); GL32.glLinkProgram(this.id); - + vertShader.free(); // important! fragShader.free(); // important! - + int status = GL32.glGetProgrami(this.id, GL32.GL_LINK_STATUS); if (status != GL32.GL_TRUE) { String message = "Shader Link Error. Details: "+GL32.glGetProgramInfoLog(this.id); @@ -70,7 +78,7 @@ public class ShaderProgram } GL32.glUseProgram(id); // This HAVE to be a direct call to prevent calling the overloaded version } - + /** This will bind ShaderProgram */ public void bind() { @@ -101,7 +109,13 @@ public class ShaderProgram if (i==-1) throw new RuntimeException("Attribute name not found: "+name); return i; } - + // Same as above but without throwing errors. + // Return -1 if attribute doesn't exist or has been optimized out + public int tryGetAttributeLocation(CharSequence name) + { + return GL32.glGetAttribLocation(id, name); + } + /** WARNING: Slow native call! Cache it if possible! * Gets the location of a uniform variable with specified name. * Calls GL20.glGetUniformLocation(id, name) @@ -117,6 +131,13 @@ public class ShaderProgram return i; } + // Same as above but without throwing errors. + // Return -1 if uniform doesn't exist or has been optimized out + public int tryGetUniformLocation(CharSequence name) + { + return GL32.glGetUniformLocation(id, name); + } + /** Requires ShaderProgram binded. */ public void setUniform(int location, boolean value) { diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index de5e845e6..d5ee914a4 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -229,7 +229,7 @@ public interface ILodConfigWrapperSingleton extends IBindable interface IAdvancedFog { String DESC = "Advanced settings for fog rendering. Has no effect if Far Fog is not drawn \n" - + "See https://www.desmos.com/calculator/drzzlfmur9 for how setting effect the curve."; + + "See https://www.desmos.com/calculator/?????? for how setting effect the curve."; MinDefaultMax FOG_RANGE = new MinDefaultMax<>(0.0,1.0, Math.sqrt(2.0)); @@ -271,16 +271,16 @@ public interface ILodConfigWrapperSingleton extends IBindable double getFarFogMax(); void setFarFogMax(double newFarFogMax); - FogSetting.Type FAR_FOG_TYPE_DEFAULT = FogSetting.Type.EXPONENTIAL_SQUARED; + FogSetting.FogType FAR_FOG_TYPE_DEFAULT = FogSetting.FogType.EXPONENTIAL_SQUARED; String FAR_FOG_TYPE_DESC = "" + " How the fog thickness should be calculated from distance? \n" + "\n" - + " "+ FogSetting.Type.LINEAR + ": Linear based on distance (will ignore 'density')\n" - + " "+ FogSetting.Type.EXPONENTIAL + ": 1/(e^(distance*density)) \n" - + " "+ FogSetting.Type.EXPONENTIAL_SQUARED + ": 1/(e^((distance*density)^2) \n"; + + " "+ FogSetting.FogType.LINEAR + ": Linear based on distance (will ignore 'density')\n" + + " "+ FogSetting.FogType.EXPONENTIAL + ": 1/(e^(distance*density)) \n" + + " "+ FogSetting.FogType.EXPONENTIAL_SQUARED + ": 1/(e^((distance*density)^2) \n"; //+ " "+ FogSetting.Type.TEXTURE_BASED + ": Use a provided 1D texture mapping (will ignore 'density', 'min', and 'max')\n"; - FogSetting.Type getFarFogType(); - void setFarFogType(FogSetting.Type newFarFogType); + FogSetting.FogType getFarFogType(); + void setFarFogType(FogSetting.FogType newFarFogType); MinDefaultMax FAR_FOG_DENSITY_MIN_DEFAULT_MAX = new MinDefaultMax<>(0.01,2.5, 50.0); String FAR_FOG_DENSITY_DESC = "" @@ -293,37 +293,61 @@ public interface ILodConfigWrapperSingleton extends IBindable String DESC = "Advanced settings for how far fog interacts with height. Has no effect if Far Fog is not drawn \n" + "See https://www.desmos.com/calculator/drzzlfmur9 for how setting effect the curve."; - HeightFogMode HEIGHT_FOG_MODE_DEFAULT = HeightFogMode.BASIC; - String HEIGHT_FOG_MODE_DESC = "" + HeightFogMixMode HEIGHT_FOG_MIX_MODE_DEFAULT = HeightFogMixMode.BASIC; + String HEIGHT_FOG_MIX_MODE_DESC = "" + " How the height should effect the fog thickness combined with the normal function? \n" + "\n" - + " " + HeightFogMode.BASIC + ": No special height fog effect. Fog is calculated based on camera distance \n" - + " " + HeightFogMode.IGNORE_HEIGHT + ": Ignore height completely. Fog is calculated based on horizontal distance \n" - + " " + HeightFogMode.ADDITION + ": The calculated Height Fog thickness is added to Horizontal Fog thickness \n" - + " " + HeightFogMode.MAX + ": Use the max of Height Fog thickness and Horizontal Fog thickness \n" - + " " + HeightFogMode.SQUARED_ADDITION + ": Height Fog thickness and Horizontal Fog thickness is added via squared scaling \n" + + " " + HeightFogMixMode.BASIC + ": No special height fog effect. Fog is calculated based on camera distance \n" + + " " + HeightFogMixMode.IGNORE_HEIGHT + ": Ignore height completely. Fog is calculated based on horizontal distance \n" + + " " + HeightFogMixMode.ADDITION + ": heightFog + farFog \n" + + " " + HeightFogMixMode.MAX + ": max(heightFog, farFog) \n" + + " " + HeightFogMixMode.MULTIPLY + ": heightFog * farFog \n" + + " " + HeightFogMixMode.INVERSE_MULTIPLY + ": 1 - (1-heightFog) * (1-farFog) \n" + + " " + HeightFogMixMode.LIMITED_ADDITION + ": farFog + max(farFog, heightFog) \n" + + " " + HeightFogMixMode.MULTIPLY_ADDITION + ": farFog + farFog * heightFog \n" + + " " + HeightFogMixMode.INVERSE_MULTIPLY_ADDITION + ": farFog + 1 - (1-heightFog) * (1-farFog) \n" + + " " + HeightFogMixMode.AVERAGE + ": farFog*0.5 + heightFog*0.5 \n" + "\n" + " Note that for 'BASIC' mode and 'IGNORE_HEIGHT' mode, fog settings for height fog has no effect.\n"; + HeightFogMixMode getHeightFogMixMode(); + void setHeightFogMixMode(HeightFogMixMode newHeightFogMixMode); + + HeightFogMode HEIGHT_FOG_MODE_DEFAULT = HeightFogMode.ABOVE_AND_BELOW_CAMERA; + String HEIGHT_FOG_MODE_DESC = "" + + " Where should the height fog be located? \n" + + "\n" + + " " + HeightFogMode.ABOVE_CAMERA + ": Height fog starts from camera to the sky \n" + + " " + HeightFogMode.BELOW_CAMERA + ": Height fog starts from camera to the void \n" + + " " + HeightFogMode.ABOVE_AND_BELOW_CAMERA + ": Height fog starts from camera to both the sky and the void \n" + + " " + HeightFogMode.ABOVE_SET_HEIGHT + ": Height fog starts from a set height to the sky \n" + + " " + HeightFogMode.BELOW_SET_HEIGHT + ": Height fog starts from a set height to the void \n" + + " " + HeightFogMode.ABOVE_AND_BELOW_SET_HEIGHT + ": Height fog starts from a set height to both the sky and the void \n" + + "\n"; HeightFogMode getHeightFogMode(); - void setHeightFogType(HeightFogMode newHeightFogMode); + void setHeightFogMode(HeightFogMode newHeightFogMode); + + MinDefaultMax HEIGHT_FOG_HEIGHT_MIN_DEFAULT_MAX = new MinDefaultMax<>(-4096., 70., 4096.); + String HEIGHT_FOG_HEIGHT_DESC = "" + + " If the height fog is calculated around a set height, what is that height position? \n" + + "\n"; + double getHeightFogHeight(); + void setHeightFogHeight(double newHeightFogHeight); MinDefaultMax HEIGHT_FOG_START_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue, 0.0, FOG_RANGE.maxValue); String HEIGHT_FOG_START_DESC = "" - + " Where should the far fog start? \n" + + " How far the start of height fog should offset? \n" + "\n" - + " '0.0': Fog start at player's position.\n" - + " '1.0': The fog-start's circle fit just in the lod render distance square.\n" - + " '1.414': The lod render distance square fit just in the fog-start's circle.\n"; + + " '0.0': Fog start with no offset.\n" + + " '1.0': Fog start with offset of the entire world's height. (Include depth)\n"; double getHeightFogStart(); void setHeightFogStart(double newHeightFogStart); MinDefaultMax HEIGHT_FOG_END_MIN_DEFAULT_MAX = new MinDefaultMax<>(FOG_RANGE.minValue, 1.0, FOG_RANGE.maxValue); String HEIGHT_FOG_END_DESC = "" - + " Where should the far fog end? \n" + + " How far the end of height fog should offset? \n" + "\n" - + " '0.0': Fog end at player's position.\n" - + " '1.0': The fog-end's circle fit just in the lod render distance square.\n" - + " '1.414': The lod render distance square fit just in the fog-end's circle.\n"; + + " '0.0': Fog end with no offset.\n" + + " '1.0': Fog end with offset of the entire world's height. (Include depth)\n"; double getHeightFogEnd(); void setHeightFogEnd(double newHeightFogEnd); @@ -345,16 +369,16 @@ public interface ILodConfigWrapperSingleton extends IBindable double getHeightFogMax(); void setHeightFogMax(double newHeightFogMax); - FogSetting.Type HEIGHT_FOG_TYPE_DEFAULT = FogSetting.Type.EXPONENTIAL_SQUARED; + FogSetting.FogType HEIGHT_FOG_TYPE_DEFAULT = FogSetting.FogType.EXPONENTIAL_SQUARED; String HEIGHT_FOG_TYPE_DESC = "" + " How the fog thickness should be calculated from height? \n" + "\n" - + " " + FogSetting.Type.LINEAR + ": Linear based on height (will ignore 'density')\n" - + " " + FogSetting.Type.EXPONENTIAL + ": 1/(e^(height*density)) \n" - + " " + FogSetting.Type.EXPONENTIAL_SQUARED + ": 1/(e^((height*density)^2) \n"; + + " " + FogSetting.FogType.LINEAR + ": Linear based on height (will ignore 'density')\n" + + " " + FogSetting.FogType.EXPONENTIAL + ": 1/(e^(height*density)) \n" + + " " + FogSetting.FogType.EXPONENTIAL_SQUARED + ": 1/(e^((height*density)^2) \n"; //+ " "+ FogSetting.Type.TEXTURE_BASED + ": Use a provided 1D texture mapping (will ignore 'density', 'min', and 'max')\n"; - FogSetting.Type getHeightFogType(); - void setHeightFogType(FogSetting.Type newFarFogType); + FogSetting.FogType getHeightFogType(); + void setHeightFogType(FogSetting.FogType newFarFogType); MinDefaultMax HEIGHT_FOG_DENSITY_MIN_DEFAULT_MAX = new MinDefaultMax<>(0.01, 2.5, 50.0); String HEIGHT_FOG_DENSITY_DESC = "" diff --git a/src/main/resources/assets/lod/lang/en_us.json b/src/main/resources/assets/lod/lang/en_us.json index 962170490..038991f9c 100644 --- a/src/main/resources/assets/lod/lang/en_us.json +++ b/src/main/resources/assets/lod/lang/en_us.json @@ -59,6 +59,74 @@ "Disable vanilla fog", "DistantHorizons.config.client.graphics.fogQuality.disableVanillaFog.@tooltip": "§6True:§r disables Minecraft's fog on vanilla chunks.\n§6False:§r Minecraft renders fog like normal.\n\nMay cause issues with other mods that edit fog.\nDisable if vanilla chunks are completely covered in fog.", + + "DistantHorizons.config.client.graphics.fogQuality.advancedFog": + "Advanced Fog Options", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogStart": +"Far Fog Start", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogEnd": + "Far Fog End", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogMin": + "Far Fog Min", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogMax": + "Far Fog Max", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogType": + "Far Fog Type", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogDensity": + "Far Fog Density", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog": + "Height Fog Options", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMixMode": + "Height Fog Mix Mode", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMode": + "Height Fog Mode", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogHeight": + "Height Fog Set Height", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogStart": + "Height Fog Start", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogEnd": + "Height Fog End", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMin": + "Height Fog Min", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMax": + "Height Fog Max", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogType": + "Height Fog Type", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogDensity": + "Height Fog Density", + + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogStart.@tooltip": + "Where should the far fog start? \n\n '0.0': Fog start at player's position.\n '1.0': The fog-start's circle fit just in the lod render distance square.\n'1.414': The lod render distance square fit just in the fog-start's circle.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogEnd.@tooltip": + "Where should the far fog end? \n\n '0.0': Fog end at player's position.\n '1.0': The fog-end's circle fit just in the lod render distance square.\n'1.414': The lod render distance square fit just in the fog-end's circle.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogMin.@tooltip": + "What is the minimum fog thickness? \n\n '0.0': No fog at all.\n '1.0': Fully fog color.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogMax.@tooltip": + "What is the maximum fog thickness? \n\n '0.0': No fog at all.\n '1.0': Fully fog color.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogType.@tooltip": + "How the fog thickness should be calculated from distance?\n\nLINEAR: Linear based on distance (will ignore 'density')\nEXPONENTIAL: 1/(e^(distance*density)) \nEXPONENTIAL_SQUARED: 1/(e^((distance*density)^2) \n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.farFogDensity.@tooltip": + "What is the fog density? ", + + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMixMode.@tooltip": + "How the height should effect the fog thickness combined with the normal function? \n\nBASIC: No special height fog effect. Fog is calculated based on camera distance \nIGNORE_HEIGHT: Ignore height completely. Fog is calculated based on horizontal distance \nADDITION: heightFog + farFog \nMAX: max(heightFog, farFog) \nMULTIPLY: heightFog * farFog \nINVERSE_MULTIPLY: 1 - (1-heightFog) * (1-farFog) \nLIMITED_ADDITION: farFog + max(farFog, heightFog) \nMULTIPLY_ADDITION: farFog + farFog * heightFog \nINVERSE_MULTIPLY_ADDITION: farFog + 1 - (1-heightFog) * (1-farFog) \nAVERAGE: farFog*0.5 + heightFog*0.5 \n\nNote that for 'BASIC' mode and 'IGNORE_HEIGHT' mode, fog settings for height fog has no effect.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMode.@tooltip": + "Where should the height fog be located? \n\nABOVE_CAMERA: Height fog starts from camera to the sky \nBELOW_CAMERA: Height fog starts from camera to the void \nABOVE_AND_BELOW_CAMERA: Height fog starts from camera to both the sky and the void \nABOVE_SET_HEIGHT: Height fog starts from a set height to the sky \nBELOW_SET_HEIGHT: Height fog starts from a set height to the void \nABOVE_AND_BELOW_SET_HEIGHT: Height fog starts from a set height to both the sky and the void \n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogHeight.@tooltip": + "If the height fog is calculated around a set height, what is that height position? ", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogStart.@tooltip": + "How far the start of height fog should offset? \n\n '0.0': Fog start with no offset.\n '1.0': Fog start with offset of the entire world's height. (Include depth)\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogEnd.@tooltip": + "How far the end of height fog should offset? \n\n '0.0': Fog end with no offset.\n '1.0': Fog end with offset of the entire world's height. (Include depth)\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMin.@tooltip": + "What is the minimum fog thickness? \n\n '0.0': No fog at all.\n '1.0': Fully fog color.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogMax.@tooltip": + "What is the maximum fog thickness? \n\n '0.0': No fog at all.\n '1.0': Fully fog color.\n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogType.@tooltip": + "How the fog thickness should be calculated from height? \n\nLINEAR: Linear based on height (will ignore 'density')\nEXPONENTIAL: 1/(e^(height*density)) \nEXPONENTIAL_SQUARED: 1/(e^((height*density)^2) \n", + "DistantHorizons.config.client.graphics.fogQuality.advancedFog.heightFog.heightFogDensity.@tooltip": + "What is the fog density? ", + "DistantHorizons.config.client.graphics.advancedGraphics": "Advanced quality option", "DistantHorizons.config.client.graphics.advancedGraphics.lodTemplate": @@ -205,6 +273,44 @@ "Use world fog", "DistantHorizons.config.enum.FogColorMode.USE_SKY_COLOR": "Use sky color", + "DistantHorizons.config.enum.FogType.LINEAR": + "Linear", + "DistantHorizons.config.enum.FogType.EXPONENTIAL": + "Exponential", + "DistantHorizons.config.enum.FogType.EXPONENTIAL_SQUARED": + "Exponential Squared", + "DistantHorizons.config.enum.HeightFogMode.ABOVE_CAMERA": + "Above Camera", + "DistantHorizons.config.enum.HeightFogMode.BELOW_CAMERA": + "Below Camera", + "DistantHorizons.config.enum.HeightFogMode.ABOVE_AND_BELOW_CAMERA": + "Above And Below Camera", + "DistantHorizons.config.enum.HeightFogMode.ABOVE_SET_HEIGHT": + "Above Set Height", + "DistantHorizons.config.enum.HeightFogMode.BELOW_SET_HEIGHT": + "Below Set Height", + "DistantHorizons.config.enum.HeightFogMode.ABOVE_AND_BELOW_SET_HEIGHT": + "Above And Below Set Height", + "DistantHorizons.config.enum.HeightFogMixMode.BASIC": + "Basic", + "DistantHorizons.config.enum.HeightFogMixMode.IGNORE_HEIGHT": + "Ignore Height", + "DistantHorizons.config.enum.HeightFogMixMode.ADDITION": + "Addition", + "DistantHorizons.config.enum.HeightFogMixMode.MAX": + "Max", + "DistantHorizons.config.enum.HeightFogMixMode.MULTIPLY": + "Multiply", + "DistantHorizons.config.enum.HeightFogMixMode.INVERSE_MULTIPLY": + "Inverse Multiply", + "DistantHorizons.config.enum.HeightFogMixMode.LIMITED_ADDITION": + "Limited Addition", + "DistantHorizons.config.enum.HeightFogMixMode.MULTIPLY_ADDITION": + "Multiply Addition", + "DistantHorizons.config.enum.HeightFogMixMode.INVERSE_MULTIPLY_ADDITION": + "Inverse Multiply Addition", + "DistantHorizons.config.enum.HeightFogMixMode.AVERAGE": + "Average", "DistantHorizons.config.enum.LodTemplate.CUBIC": "Cubic", "DistantHorizons.config.enum.LodTemplate.TRIANGULAR": diff --git a/src/main/resources/shaders/flat_shaded.frag b/src/main/resources/shaders/flat_shaded.frag index c9517ed58..60411fbe1 100644 --- a/src/main/resources/shaders/flat_shaded.frag +++ b/src/main/resources/shaders/flat_shaded.frag @@ -1,25 +1,42 @@ -#version 150 core in vec4 vertexColor; in vec3 vertexWorldPos; +in float vertexYPos; out vec4 fragColor; -uniform bool fogEnabled; -uniform bool nearFogEnabled; -uniform bool farFogEnabled; - +uniform float fogScale; +uniform float fogVerticalScale; uniform float nearFogStart; -uniform float nearFogEnd; -uniform float farFogStart; -uniform float farFogEnd; +uniform float nearFogLength; +uniform int fullFogMode; + +/* ========MARCO DEFINED BY RUNTIME CODE GEN========= + +float farFogStart; +float farFogLength; +float farFogMin; +float farFogRange; +float farFogDensity; + +float heightFogStart; +float heightFogLength; +float heightFogMin; +float heightFogRange; +float heightFogDensity; +*/ + uniform vec4 fogColor; - // method definitions -float getFogAlpha(float start, float end, float dist); - - +// ==== The below 5 methods will be run-time generated. ==== +float getNearFogThickness(float dist); +float getFarFogThickness(float dist); +float getHeightFogThickness(float dist); +float calculateFarFogDepth(float horizontal, float dist); +float calculateHeightFogDepth(float vertical, float realY); +float mixFogThickness(float near, float far, float height); +// ========================================================= /** * Fragment Shader @@ -29,55 +46,46 @@ float getFogAlpha(float start, float end, float dist); */ void main() { - // TODO: add a white texture to support Optifine shaders - //vec4 textureColor = texture(texImage, textureCoord); - //fragColor = vertexColor * textureColor; - - vec4 returnColor; - if (fogEnabled) - { - // add fog - - // no fog by default - float fogAlpha = 0; - - float dist = length(vertexWorldPos); + if (fullFogMode != 0) { + returnColor = vec4(fogColor.rgb, 1.0); + } else { + // TODO: add a white texture to support Optifine shaders + //vec4 textureColor = texture(texImage, textureCoord); + //fragColor = vertexColor * textureColor; + + float horizontalDist = length(vertexWorldPos.xz) * fogScale; + float heightDist = calculateHeightFogDepth( + vertexWorldPos.y, vertexYPos) * fogVerticalScale; + float farDist = calculateFarFogDepth(horizontalDist, + length(vertexWorldPos.xyz) * fogScale); + + float nearFogThickness = getNearFogThickness(horizontalDist); + float farFogThickness = getFarFogThickness(farDist); + float heightFogThickness = getHeightFogThickness(heightDist); + float mixedFogThickness = clamp(mixFogThickness( + nearFogThickness, farFogThickness, heightFogThickness), 0.0, 1.0); + + returnColor = mix(vertexColor, vec4(fogColor.rgb, 1.0), mixedFogThickness); - // less than because nearFogStart is farther away than nearFogEnd - if (nearFogEnabled && dist < nearFogStart) - { - fogAlpha = getFogAlpha(nearFogStart, nearFogEnd, dist); - } - else if (farFogEnabled) - { - fogAlpha = getFogAlpha(farFogStart, farFogEnd, dist); - } - - returnColor = mix(vertexColor, vec4(fogColor.xyz, 1), fogAlpha); } - else - { - // simple flat color - returnColor = vertexColor; - } - - //fragColor = vec4(0.7,0.6,0.5,1.0); + //fragColor = vec4(0.7,0.6,0.5,1.0); fragColor = vec4(returnColor.rgb,1.0); } - - - -/** - * Returns the fog strength for the given fragment. - * This is the same implementation as legacy OpenGL's Linear fog option. - * 1 = completely opaque fog - * 0 = no fog - */ -float getFogAlpha(float start, float end, float dist) -{ - float fogAlpha = 1 - ((end - dist) / (end - start)); - return clamp(fogAlpha, 0, 1); +float linearFog(float x, float fogStart, float fogLength, float fogMin, float fogRange) { + x = clamp((x-fogStart)/fogLength, 0.0, 1.0); + return fogMin + fogRange * x; } +float exponentialFog(float x, float fogStart, float fogLength, + float fogMin, float fogRange, float fogDensity) { + x = max((x-fogStart)/fogLength, 0.0) * fogDensity; + return fogMin + fogRange - fogRange/exp(x); +} + +float exponentialSquaredFog(float x, float fogStart, float fogLength, + float fogMin, float fogRange, float fogDensity) { + x = max((x-fogStart)/fogLength, 0.0) * fogDensity; + return fogMin + fogRange - fogRange/exp(x*x); +} \ No newline at end of file diff --git a/src/main/resources/shaders/standard.vert b/src/main/resources/shaders/standard.vert index 6b35cd1ab..04ab6ff4d 100644 --- a/src/main/resources/shaders/standard.vert +++ b/src/main/resources/shaders/standard.vert @@ -5,9 +5,11 @@ in vec4 color; out vec4 vertexColor; out vec3 vertexWorldPos; +out float vertexYPos; -uniform mat4 modelViewMatrix; -uniform mat4 projectionMatrix; +uniform mat4 combinedMatrix; +uniform vec3 modelOffset; +uniform float worldYOffset; uniform int worldSkyLight; uniform sampler2D lightMap; @@ -24,18 +26,11 @@ uniform sampler2D lightMap; */ void main() { - vec4 worldSpacePos = modelViewMatrix * vec4(vPosition.xyz,1); + vertexWorldPos = vPosition.xyz + modelOffset; + vertexYPos = vPosition.y + worldYOffset; + float light = (vPosition.a+0.5) / 256.0; - vertexColor = color * texture(lightMap, vec2(light,0.5)); - - vertexWorldPos = worldSpacePos.xyz; - // vec4 pos = projectionMatrix * worldSpacePos; - gl_Position = projectionMatrix * worldSpacePos; - /*pos.a = 1.0; - if (pos.x>0) pos.x=-1; else pos.x=1; - if (pos.y>0) pos.y=-1; else pos.y=1; - pos.z = 0.5; - gl_Position = pos;*/ + gl_Position = combinedMatrix * vec4(vertexWorldPos, 1.0); } From 2907c8e3e7bbbe570328057b41c2baf116ddec37 Mon Sep 17 00:00:00 2001 From: TomTheFurry <46843632+TomTheFurry@users.noreply.github.com> Date: Wed, 16 Mar 2022 18:51:43 +0800 Subject: [PATCH 13/13] Fixed a deadlock on shutting down BufferBuilders --- .../builders/bufferBuilding/LodBufferBuilderFactory.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java index 4ce2dd361..d4c534e98 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java @@ -273,15 +273,13 @@ public class LodBufferBuilderFactory { ApiShared.LOGGER.error("LodBufferBuilder timed out: ", te); resetThreadPools(true); } - } catch (InterruptedException ie) { } catch (Exception e) { ApiShared.LOGGER.error("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: ", e); - } finally { - if (ENABLE_EVENT_LOGGING) ApiShared.LOGGER.info("BufferBuilderStarter unlocked the region lock!"); - regionsListLock.unlock(); } } catch (InterruptedException ie) { } finally { + regionsListLock.unlock(); + if (ENABLE_EVENT_LOGGING) ApiShared.LOGGER.info("BufferBuilderStarter unlocked the region lock!"); builderThreadRunning = false; } }