diff --git a/LICENSE-DEPENDENCIES b/LICENSE-DEPENDENCIES index 72cabceee9..737e66c03f 100644 --- a/LICENSE-DEPENDENCIES +++ b/LICENSE-DEPENDENCIES @@ -1,8 +1,3 @@ Incompatible licenses: -glsl-transformer is licensed under the glsl-transformer Noncommercial License 1.0.0. Details on this can be found in https://github.com/IrisShaders/glsl-transformer/blob/main/LICENSE. -The license text is short and easy to understand, but the gist is that you may distribute unmodified editions of this library and them in new works, under the condition that you qualify as a noncommercial entity. If you need to modify it, you may only do so in private or by contributing the changes back to the IrisShaders/glsl-transformer repository under the Contributor License Agreement. Using and distributing this library as part of a noncommercial, meaning access to it is not conditioned on payment or other compensation, Minecraft mod or related software falls under the allowed purposes. You are required to obtain a commercial license for using this library for any purpose other than a noncommercial one. - -This license is not applicable if linking with a program (Iris) containing glsl-transformer, unless the linker interacts with the library's API directly. - -tl;dr: If you intend to just depend on Iris and need to depend on the transformer due to that, you're fine. If you intend to use the transformer in any way, you must follow the license as followed above. +glsl-transformer is licensed under the GNU Affero General Public License version 3. This may affect your ability to distribute Iris. diff --git a/README.md b/README.md index 70e63fdd26..fecad58c7d 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,6 @@ So, if you want to distribute a Forge port of Iris, we'd prefer if you let us kn All code in this (Iris) repository is completely free and open source, and you are free to read, distribute, and modify the code as long as you abide by the (fairly reasonable) terms of the [GNU LGPLv3 license](https://github.com/IrisShaders/Iris/blob/master/LICENSE). -Dependencies may not be under an applicable license: See the [Incompatible Dependencies](https://github.com/IrisShaders/Iris/blob/master/LICENSE-DEPENDENCIES) page for more information. - -You are not allowed to redistribute Iris commerically or behind a paywall, unless you get a commercial license for GLSL Transformer. See above for more information. +glsl-transformer is licensed under the GNU Affero General Public License version 3. This may affect your ability to distribute Iris. Though it's not legally required, I'd appreciate it if you could ask before hosting your own public downloads for compiled versions of Iris. Though if you want to add the mod to a site like MCBBS, that's fine, no need to ask me. diff --git a/build.gradle.kts b/build.gradle.kts index c67531db18..7a25cfdd90 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ object Constants { const val FABRIC_API_VERSION: String = "0.96.0+1.20.4" // https://semver.org/ - const val MOD_VERSION: String = "1.7.0" + const val MOD_VERSION: String = "1.7.2" const val CUSTOM_SODIUM: Boolean = false const val CUSTOM_SODIUM_NAME: String = "" @@ -33,6 +33,7 @@ repositories { includeGroup("maven.modrinth") } } + maven("https://maven.covers1624.net/") } plugins { @@ -53,6 +54,21 @@ base { } loom { + runs { + create("clientWithQuickplay") { + client() + isIdeConfigGenerated = true + programArgs("--launch_target", "net.fabricmc.loader.impl.launch.knot.KnotClient") + mainClass.set("net.covers1624.devlogin.DevLogin") + projectDir.resolve("run").resolve("mods").resolve(Constants.MINECRAFT_VERSION).mkdirs() + vmArgs("-Dfabric.modsFolder=" + projectDir.resolve("run").resolve("mods").resolve(Constants.MINECRAFT_VERSION).absolutePath) + programArgs("--quickPlaySingleplayer", "World For " + Constants.MINECRAFT_VERSION) + if (Constants.ACTIVATE_RENDERDOC && DefaultNativePlatform.getCurrentOperatingSystem().isLinux) { + environmentVariable("LD_PRELOAD", "/usr/lib/librenderdoc.so") + } + } + } + mixin { useLegacyMixinAp = false } @@ -134,11 +150,12 @@ dependencies { minecraft(group = "com.mojang", name = "minecraft", version = Constants.MINECRAFT_VERSION) mappings(loom.officialMojangMappings()) modImplementation(group = "net.fabricmc", name = "fabric-loader", version = Constants.FABRIC_LOADER_VERSION) + localRuntime("net.covers1624:DevLogin:0.1.0.5") - include("org.antlr:antlr4-runtime:4.11.1") - modImplementation("org.antlr:antlr4-runtime:4.11.1") - include("io.github.douira:glsl-transformer:2.0.0-pre13") - modImplementation("io.github.douira:glsl-transformer:2.0.0-pre13") + include("org.antlr:antlr4-runtime:4.13.1") + modImplementation("org.antlr:antlr4-runtime:4.13.1") + include("io.github.douira:glsl-transformer:2.0.1") + modImplementation("io.github.douira:glsl-transformer:2.0.1") include("org.anarres:jcpp:1.4.14") modImplementation("org.anarres:jcpp:1.4.14") @@ -173,6 +190,7 @@ tasks { environment("LD_PRELOAD", "/usr/lib/librenderdoc.so") } } + getByName("compileDesktopJava") { sourceCompatibility = JavaVersion.VERSION_1_8.toString() targetCompatibility = JavaVersion.VERSION_1_8.toString() diff --git a/src/main/java/kroppeb/stareval/function/AbstractTypedFunction.java b/src/main/java/kroppeb/stareval/function/AbstractTypedFunction.java index b67b78c1cd..c0f1b75dcf 100644 --- a/src/main/java/kroppeb/stareval/function/AbstractTypedFunction.java +++ b/src/main/java/kroppeb/stareval/function/AbstractTypedFunction.java @@ -1,6 +1,7 @@ package kroppeb.stareval.function; import java.util.Arrays; +import java.util.Objects; public abstract class AbstractTypedFunction implements TypedFunction { private final Type returnType; @@ -41,4 +42,26 @@ public boolean isPure() { public int priority() { return this.priority; } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AbstractTypedFunction func) { + return Objects.equals(returnType, func.returnType) && + Arrays.equals(parameters, func.parameters) && + priority == func.priority && + isPure == func.isPure; + } + + return false; + } + + @Override + public int hashCode() { + return Objects.hash(returnType, Arrays.hashCode(parameters), priority, isPure); + } + + @Override + public String toString() { + return TypedFunction.format(this, "unknown"); + } } diff --git a/src/main/java/kroppeb/stareval/function/TypedFunction.java b/src/main/java/kroppeb/stareval/function/TypedFunction.java index b9f2837c29..bed05058ee 100644 --- a/src/main/java/kroppeb/stareval/function/TypedFunction.java +++ b/src/main/java/kroppeb/stareval/function/TypedFunction.java @@ -3,6 +3,7 @@ import kroppeb.stareval.expression.Expression; import java.util.Arrays; +import java.util.Objects; import java.util.stream.Collectors; public interface TypedFunction { @@ -53,6 +54,19 @@ public Type type() { public boolean constant() { return this.isConstant; } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Parameter p) { + return Objects.equals(type, p.type) && Objects.equals(isConstant, p.isConstant); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(type) + 3192 + Objects.hashCode(isConstant); + } } } diff --git a/src/main/java/net/irisshaders/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/irisshaders/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java index e2023683d0..69460fba16 100644 --- a/src/main/java/net/irisshaders/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ b/src/main/java/net/irisshaders/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -1,5 +1,7 @@ package net.irisshaders.batchedentityrendering.impl.wrappers; +import net.irisshaders.batchedentityrendering.impl.BlendingStateHolder; +import net.irisshaders.batchedentityrendering.impl.TransparencyType; import net.irisshaders.batchedentityrendering.impl.WrappableRenderType; import net.irisshaders.batchedentityrendering.mixin.RenderTypeAccessor; import net.minecraft.client.renderer.RenderType; @@ -8,7 +10,7 @@ import java.util.Objects; import java.util.Optional; -public class TaggingRenderTypeWrapper extends RenderType implements WrappableRenderType { +public class TaggingRenderTypeWrapper extends RenderType implements WrappableRenderType, BlendingStateHolder { private final int tag; private final RenderType wrapped; @@ -58,11 +60,21 @@ public boolean equals(@Nullable Object object) { public int hashCode() { // Add one so that we don't have the exact same hash as the wrapped object. // This means that we won't have a guaranteed collision if we're inserted to a map alongside the unwrapped object. - return this.wrapped.hashCode() + 1; + return this.wrapped.hashCode() + this.tag + 1; } @Override public String toString() { return "tagged(" + tag + "):" + this.wrapped.toString(); } + + @Override + public TransparencyType getTransparencyType() { + return ((BlendingStateHolder) wrapped).getTransparencyType(); + } + + @Override + public void setTransparencyType(TransparencyType transparencyType) { + ((BlendingStateHolder) wrapped).setTransparencyType(transparencyType); + } } diff --git a/src/main/java/net/irisshaders/batchedentityrendering/mixin/MixinLevelRenderer_EntityListSorting.java b/src/main/java/net/irisshaders/batchedentityrendering/mixin/MixinLevelRenderer_EntityListSorting.java index ad8c9a93ea..c1a35e3da5 100644 --- a/src/main/java/net/irisshaders/batchedentityrendering/mixin/MixinLevelRenderer_EntityListSorting.java +++ b/src/main/java/net/irisshaders/batchedentityrendering/mixin/MixinLevelRenderer_EntityListSorting.java @@ -1,5 +1,7 @@ package net.irisshaders.batchedentityrendering.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.world.entity.Entity; @@ -40,17 +42,15 @@ public class MixinLevelRenderer_EntityListSorting { @Shadow private ClientLevel level; - @ModifyVariable(method = "renderLevel", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/lang/Iterable;iterator()Ljava/util/Iterator;"), - slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderBuffers;bufferSource()Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;"), - to = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRenderDispatcher;shouldRender(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/client/renderer/culling/Frustum;DDD)Z")), allow = 1) - private Iterator batchedentityrendering$sortEntityList(Iterator iterator) { + @WrapOperation(method = "renderLevel", at = @At(value = "INVOKE", target = "Ljava/lang/Iterable;iterator()Ljava/util/Iterator;")) + private Iterator batchedentityrendering$sortEntityList(Iterable instance, Operation> original) { // Sort the entity list first in order to allow vanilla's entity batching code to work better. this.level.getProfiler().push("sortEntityList"); Map, List> sortedEntities = new HashMap<>(); List entities = new ArrayList<>(); - iterator.forEachRemaining(entity -> { + original.call(instance).forEachRemaining(entity -> { sortedEntities.computeIfAbsent(entity.getType(), entityType -> new ArrayList<>(32)).add(entity); }); diff --git a/src/main/java/net/irisshaders/iris/Iris.java b/src/main/java/net/irisshaders/iris/Iris.java index 0dfb291fad..bd43a28e46 100644 --- a/src/main/java/net/irisshaders/iris/Iris.java +++ b/src/main/java/net/irisshaders/iris/Iris.java @@ -10,6 +10,7 @@ import net.irisshaders.iris.compat.dh.DHCompat; import net.irisshaders.iris.config.IrisConfig; import net.irisshaders.iris.gl.GLDebug; +import net.irisshaders.iris.gl.buffer.ShaderStorageBufferHolder; import net.irisshaders.iris.gl.shader.ShaderCompileException; import net.irisshaders.iris.gl.shader.StandardMacros; import net.irisshaders.iris.gui.debug.DebugLoadFailedGridScreen; @@ -97,7 +98,6 @@ public class Iris { static { if (!BuildConfig.ACTIVATE_RENDERDOC && FabricLoader.getInstance().isDevelopmentEnvironment() && System.getProperty("user.name").contains("ims") && Util.getPlatform() == Util.OS.LINUX) { - Configuration.GLFW_LIBRARY_NAME.set("/usr/lib/libglfw.so"); } } @@ -313,6 +313,7 @@ private static boolean loadExternalShaderpack(String name) { } catch (Exception e) { logger.error("Failed to load the shaderpack \"{}\"!", name); logger.error("", e); + handleException(e); return false; } @@ -325,6 +326,19 @@ private static boolean loadExternalShaderpack(String name) { return true; } + private static void handleException(Exception e) { + if (lastDimension != null && irisConfig.areDebugOptionsEnabled()) { + Minecraft.getInstance().setScreen(new DebugLoadFailedGridScreen(Minecraft.getInstance().screen, Component.literal(e instanceof ShaderCompileException ? "Failed to compile shaders" : "Exception"), e)); + } else { + if (Minecraft.getInstance().player != null) { + Minecraft.getInstance().player.displayClientMessage(Component.translatable(e instanceof ShaderCompileException ? "iris.load.failure.shader" : "iris.load.failure.generic").append(Component.literal("Copy Info").withStyle(arg -> arg.withUnderlined(true).withColor( + ChatFormatting.BLUE).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, e.getMessage())))), false); + } else { + storedError = Optional.of(e); + } + } + } + private static Optional loadExternalZipShaderpack(Path shaderpackPath) throws IOException { FileSystem zipSystem = FileSystems.newFileSystem(shaderpackPath, Iris.class.getClassLoader()); zipFileSystem = zipSystem; @@ -356,8 +370,6 @@ private static void setShadersDisabled() { currentPack = null; fallback = false; currentPackName = "(off)"; - - logger.info("Shaders are disabled"); } public static void setDebug(boolean enable) { @@ -579,15 +591,9 @@ private static WorldRenderingPipeline createPipeline(NamespacedId dimensionId) { try { return new IrisRenderingPipeline(programs); } catch (Exception e) { - if (irisConfig.areDebugOptionsEnabled()) { - Minecraft.getInstance().setScreen(new DebugLoadFailedGridScreen(Minecraft.getInstance().screen, Component.literal(e instanceof ShaderCompileException ? "Failed to compile shaders" : "Exception"), e)); - } else { - if (Minecraft.getInstance().player != null) { - Minecraft.getInstance().player.displayClientMessage(Component.translatable(e instanceof ShaderCompileException ? "iris.load.failure.shader" : "iris.load.failure.generic").append(Component.literal("Copy Info").withStyle(arg -> arg.withUnderlined(true).withColor(ChatFormatting.BLUE).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, e.getMessage())))), false); - } else { - storedError = Optional.of(e); - } - } + handleException(e); + + ShaderStorageBufferHolder.forceDeleteBuffers(); logger.error("Failed to create shader rendering pipeline, disabling shaders!", e); // TODO: This should be reverted if a dimension change causes shaders to compile again fallback = true; diff --git a/src/main/java/net/irisshaders/iris/compat/dh/DHCompat.java b/src/main/java/net/irisshaders/iris/compat/dh/DHCompat.java index 042a2e3d63..3991078c8b 100644 --- a/src/main/java/net/irisshaders/iris/compat/dh/DHCompat.java +++ b/src/main/java/net/irisshaders/iris/compat/dh/DHCompat.java @@ -79,7 +79,7 @@ public static void run() { if (e instanceof ExceptionInInitializerError eiie) { throw new RuntimeException("Failure loading DH compat.", eiie.getCause()); } else { - throw new RuntimeException("DH 2.0 not found, yet Fabric claims it's there. Curious.", e); + throw new RuntimeException("DH found, but one or more API methods are missing. Iris requires DH [2.0.4] or DH API version [1.1.0] or newer. Please make sure you are on the latest version of DH and Iris.", e); } } else { Iris.logger.info("DH not found, and classes not found."); diff --git a/src/main/java/net/irisshaders/iris/features/FeatureFlags.java b/src/main/java/net/irisshaders/iris/features/FeatureFlags.java index 89ca843804..7bf4aa6862 100644 --- a/src/main/java/net/irisshaders/iris/features/FeatureFlags.java +++ b/src/main/java/net/irisshaders/iris/features/FeatureFlags.java @@ -14,7 +14,7 @@ public enum FeatureFlags { CUSTOM_IMAGES(() -> true, IrisRenderSystem::supportsImageLoadStore), PER_BUFFER_BLENDING(() -> true, IrisRenderSystem::supportsBufferBlending), COMPUTE_SHADERS(() -> true, IrisRenderSystem::supportsCompute), - TESSELATION_SHADERS(() -> true, IrisRenderSystem::supportsTesselation), + TESSELLATION_SHADERS(() -> true, IrisRenderSystem::supportsTesselation), ENTITY_TRANSLUCENT(() -> true, () -> true), REVERSED_CULLING(() -> true, () -> true), BLOCK_EMISSION_ATTRIBUTE(() -> true, () -> true), @@ -59,6 +59,11 @@ public static boolean isInvalid(String name) { } public static FeatureFlags getValue(String value) { + if (value.equalsIgnoreCase("TESSELATION_SHADERS")) { + // fix the sins of the past + value = "TESSELLATION_SHADERS"; + } + try { return FeatureFlags.valueOf(value.toUpperCase(Locale.US)); } catch (IllegalArgumentException e) { diff --git a/src/main/java/net/irisshaders/iris/gl/GLDebug.java b/src/main/java/net/irisshaders/iris/gl/GLDebug.java index b7d664459c..d6b26eecf3 100644 --- a/src/main/java/net/irisshaders/iris/gl/GLDebug.java +++ b/src/main/java/net/irisshaders/iris/gl/GLDebug.java @@ -311,11 +311,11 @@ public static void nameObject(int id, int object, String name) { } public static void pushGroup(int id, String name) { - debugState.pushGroup(id, name); + //debugState.pushGroup(id, name); } public static void popGroup() { - debugState.popGroup(); + //debugState.popGroup(); } private interface DebugState { diff --git a/src/main/java/net/irisshaders/iris/gl/IrisLimits.java b/src/main/java/net/irisshaders/iris/gl/IrisLimits.java index 0687f5462f..287ce4f223 100644 --- a/src/main/java/net/irisshaders/iris/gl/IrisLimits.java +++ b/src/main/java/net/irisshaders/iris/gl/IrisLimits.java @@ -9,4 +9,5 @@ public class IrisLimits { * is implemented. */ public static final int MAX_COLOR_BUFFERS = 16; + public static final boolean VK_CONFORMANCE = false; } diff --git a/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java b/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java index a63d182d4f..f4814a5b9f 100644 --- a/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java +++ b/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java @@ -44,9 +44,9 @@ public void resizeIfRelative(int width, int height) { GlStateManager._glBindBuffer(GL43C.GL_SHADER_STORAGE_BUFFER, newId); // Calculation time - int newWidth = (int) (width * info.scaleX()); - int newHeight = (int) (height * info.scaleY()); - int finalSize = (newHeight * newWidth) * info.size(); + long newWidth = (long) (width * info.scaleX()); + long newHeight = (long) (height * info.scaleY()); + long finalSize = (newHeight * newWidth) * info.size(); IrisRenderSystem.bufferStorage(GL43C.GL_SHADER_STORAGE_BUFFER, finalSize, 0); IrisRenderSystem.clearBufferSubData(GL43C.GL_SHADER_STORAGE_BUFFER, GL43C.GL_R8, 0, finalSize, GL43C.GL_RED, GL43C.GL_BYTE, new int[]{0}); IrisRenderSystem.bindBufferBase(GL43C.GL_SHADER_STORAGE_BUFFER, index, newId); diff --git a/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java b/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java index 342e1a1109..bf0a51219a 100644 --- a/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java +++ b/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java @@ -2,11 +2,15 @@ import com.mojang.blaze3d.platform.GlStateManager; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import net.irisshaders.iris.Iris; import net.irisshaders.iris.gl.IrisRenderSystem; import net.irisshaders.iris.gl.sampler.SamplerLimits; import org.lwjgl.opengl.GL43C; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; public class ShaderStorageBufferHolder { private int cachedWidth; @@ -14,6 +18,9 @@ public class ShaderStorageBufferHolder { private ShaderStorageBuffer[] buffers; private boolean destroyed; + private static List ACTIVE_BUFFERS = new ArrayList<>(); + + public ShaderStorageBufferHolder(Int2ObjectArrayMap overrides, int width, int height) { destroyed = false; cachedWidth = width; @@ -29,6 +36,7 @@ public ShaderStorageBufferHolder(Int2ObjectArrayMap overrides } buffers[index] = new ShaderStorageBuffer(index, bufferInfo); + ACTIVE_BUFFERS.add(buffers[index]); int buffer = buffers[index].getId(); if (bufferInfo.relative()) { @@ -59,6 +67,14 @@ public void hasResizedScreen(int width, int height) { } } + public static void forceDeleteBuffers() { + if (!ACTIVE_BUFFERS.isEmpty()) { + Iris.logger.warn("Found " + ACTIVE_BUFFERS.size() + " stored buffers with a total size of " + ACTIVE_BUFFERS.stream().map(ShaderStorageBuffer::getSize).reduce(0L, Long::sum) + ", forcing them to be deleted."); + ACTIVE_BUFFERS.forEach(ShaderStorageBuffer::destroy); + ACTIVE_BUFFERS.clear(); + } + } + public void setupBuffers() { if (destroyed) { throw new IllegalStateException("Tried to use destroyed buffer objects"); @@ -81,6 +97,7 @@ public int getBufferIndex(int index) { public void destroyBuffers() { for (ShaderStorageBuffer buffer : buffers) { if (buffer != null) { + ACTIVE_BUFFERS.remove(buffer); buffer.destroy(); } } diff --git a/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java b/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java index 2b95080a6c..a63ab2e30f 100644 --- a/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java +++ b/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java @@ -1,4 +1,4 @@ package net.irisshaders.iris.gl.buffer; -public record ShaderStorageInfo(int size, boolean relative, float scaleX, float scaleY) { +public record ShaderStorageInfo(long size, boolean relative, float scaleX, float scaleY) { } diff --git a/src/main/java/net/irisshaders/iris/gl/shader/StandardMacros.java b/src/main/java/net/irisshaders/iris/gl/shader/StandardMacros.java index c1e164a907..ac0a27037e 100644 --- a/src/main/java/net/irisshaders/iris/gl/shader/StandardMacros.java +++ b/src/main/java/net/irisshaders/iris/gl/shader/StandardMacros.java @@ -12,6 +12,7 @@ import net.irisshaders.iris.texture.format.TextureFormat; import net.irisshaders.iris.texture.format.TextureFormatLoader; import net.minecraft.Util; +import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GL30C; @@ -43,18 +44,24 @@ public static ImmutableList createStandardEnvironmentDefines() { ArrayList standardDefines = new ArrayList<>(); define(standardDefines, "MC_VERSION", getMcVersion()); + define(standardDefines, "IRIS_VERSION", getFormattedIrisVersion()); define(standardDefines, "MC_GL_VERSION", getGlVersion(GL20C.GL_VERSION)); define(standardDefines, "MC_GLSL_VERSION", getGlVersion(GL20C.GL_SHADING_LANGUAGE_VERSION)); define(standardDefines, getOsString()); define(standardDefines, getVendor()); define(standardDefines, getRenderer()); define(standardDefines, "IS_IRIS"); + define(standardDefines, "IRIS_TAG_SUPPORT", "2"); if (FabricLoader.getInstance().isModLoaded("distanthorizons") && DHCompat.hasRenderingEnabled()) { define(standardDefines, "DISTANT_HORIZONS"); } + if (FabricLoader.getInstance().isModLoaded("continuity")) { + define(standardDefines, "IRIS_HAS_CONNECTED_TEXTURES"); + } + define(standardDefines, "DH_BLOCK_UNKNOWN", String.valueOf(0)); define(standardDefines, "DH_BLOCK_LEAVES", String.valueOf(1)); define(standardDefines, "DH_BLOCK_STONE", String.valueOf(2)); @@ -98,6 +105,7 @@ public static ImmutableList createStandardEnvironmentDefines() { return ImmutableList.copyOf(standardDefines); } + /** * Gets the current mc version String in a 5 digit format * @@ -106,36 +114,78 @@ public static ImmutableList createStandardEnvironmentDefines() { */ public static String getMcVersion() { String version = Iris.getReleaseTarget(); - if (version == null) { - throw new IllegalStateException("Could not get the current minecraft version!"); + throw new IllegalStateException("Could not get the current Minecraft version!"); } - - String[] splitVersion = version.split("\\."); - - if (splitVersion.length < 2) { + String formattedVersion = formatVersionString(version); + if (formattedVersion == null) { Iris.logger.error("Could not parse game version \"" + version + "\""); - splitVersion = Iris.getBackupVersionNumber().split("\\."); + } else { + return formattedVersion; } + String backupVersion = Iris.getBackupVersionNumber(); + String formattedBackupVersion = formatVersionString(backupVersion); + if (formattedBackupVersion == null) { + throw new IllegalArgumentException("Could not parse backup game version \"" + version + "\""); + } else { + return formattedBackupVersion; + } + } - String major = splitVersion[0]; - String minor = splitVersion[1]; - String bugfix; - if (splitVersion.length < 3) { - bugfix = "00"; + /** + * Gets the current Iris version String in a 5 digit format + * + * @return The Iris version string + * + */ + public static String getFormattedIrisVersion() { + String rawVersion = Iris.getVersion(); + if (rawVersion == null) { + throw new IllegalArgumentException("Could not get current Iris version!"); + } + Matcher matcher = SEMVER_PATTERN.matcher(rawVersion); + if (!matcher.matches()) { + throw new IllegalArgumentException("Could not parse semantic Iris version from \"" + rawVersion + "\""); + } + String major = matcher.group("major"); + String minor = matcher.group("minor"); + String bugFix = matcher.group("bugfix"); + if (bugFix == null) { + bugFix = "0"; + } + if (major == null || minor == null) { + throw new IllegalArgumentException("Could not parse semantic Iris version from \"" + rawVersion + "\""); + } + String irisSemver = "%s.%s.%s".formatted(major, minor, bugFix); + String formattedSemver = formatVersionString(irisSemver); + if (formattedSemver == null) { + throw new IllegalArgumentException("Could not get a valid semantic version string for Iris version \"" + irisSemver + "\""); } else { - bugfix = splitVersion[2]; + return formattedSemver; } + } - if (minor.length() == 1) { - minor = 0 + minor; + /** + * + * Formats a semver string into a 122 format + * + * @param version The string version to format + * @return the formatted version in a 122 format, or null if the string is not a valid semver string. + */ + @Nullable + public static String formatVersionString(String version) { + String[] splitVersion = version.split("\\."); + if (splitVersion.length < 2) { + return null; } - if (bugfix.length() == 1) { - bugfix = 0 + bugfix; + String major = splitVersion[0]; + String minor = splitVersion[1].length() == 1 ? 0 + splitVersion[1] : splitVersion[1]; + String bugFix = splitVersion.length < 3 ? "00" : splitVersion[2]; + if (bugFix.length() == 1) { + bugFix = 0 + bugFix; } - - return major + minor + bugfix; + return major + minor + bugFix; } /** @@ -253,6 +303,8 @@ public static String getRenderer() { return "MC_GL_RENDERER_QUADRO"; } else if (renderer.startsWith("mesa")) { return "MC_GL_RENDERER_MESA"; + } else if (renderer.startsWith("apple")) { + return "MC_GL_RENDERER_APPLE"; } return "MC_GL_RENDERER_OTHER"; } diff --git a/src/main/java/net/irisshaders/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/irisshaders/iris/gui/element/ShaderPackOptionList.java index 410f44363b..1149e83d86 100644 --- a/src/main/java/net/irisshaders/iris/gui/element/ShaderPackOptionList.java +++ b/src/main/java/net/irisshaders/iris/gui/element/ShaderPackOptionList.java @@ -28,6 +28,7 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.lwjgl.glfw.GLFW; import java.io.IOException; import java.io.InputStream; @@ -86,6 +87,11 @@ public int getRowWidth() { return Math.min(400, width - 12); } + @Override + protected boolean isValidMouseClick(int i) { + return i == GLFW.GLFW_MOUSE_BUTTON_1 || i == GLFW.GLFW_MOUSE_BUTTON_2; + } + public void addHeader(Component text, boolean backButton) { this.addEntry(new HeaderEntry(this.screen, this.navigation, text, backButton)); } diff --git a/src/main/java/net/irisshaders/iris/layer/BufferSourceWrapper.java b/src/main/java/net/irisshaders/iris/layer/BufferSourceWrapper.java new file mode 100644 index 0000000000..9b654faf37 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/layer/BufferSourceWrapper.java @@ -0,0 +1,45 @@ +package net.irisshaders.iris.layer; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.irisshaders.batchedentityrendering.impl.Groupable; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; + +import java.util.function.Function; + +public class BufferSourceWrapper implements MultiBufferSource, Groupable { + private final MultiBufferSource bufferSource; + private final Function typeChanger; + + public BufferSourceWrapper(MultiBufferSource bufferSource, Function typeChanger) { + this.bufferSource = bufferSource; + this.typeChanger = typeChanger; + } + + @Override + public void startGroup() { + if (bufferSource instanceof Groupable groupable) { + groupable.startGroup(); + } + } + + @Override + public boolean maybeStartGroup() { + if (bufferSource instanceof Groupable groupable) { + return groupable.maybeStartGroup(); + } + return false; + } + + @Override + public void endGroup() { + if (bufferSource instanceof Groupable groupable) { + groupable.endGroup(); + } + } + + @Override + public VertexConsumer getBuffer(RenderType renderType) { + return bufferSource.getBuffer(typeChanger.apply(renderType)); + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/GameRendererAccessor.java b/src/main/java/net/irisshaders/iris/mixin/GameRendererAccessor.java index d51bcd3412..534efbcff3 100644 --- a/src/main/java/net/irisshaders/iris/mixin/GameRendererAccessor.java +++ b/src/main/java/net/irisshaders/iris/mixin/GameRendererAccessor.java @@ -23,4 +23,7 @@ public interface GameRendererAccessor { @Invoker double invokeGetFov(Camera camera, float tickDelta, boolean b); + + @Invoker("shouldRenderBlockOutline") + boolean shouldRenderBlockOutlineA(); } diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinBiome.java b/src/main/java/net/irisshaders/iris/mixin/MixinBiome.java index 836a85d16f..cc2de061ec 100644 --- a/src/main/java/net/irisshaders/iris/mixin/MixinBiome.java +++ b/src/main/java/net/irisshaders/iris/mixin/MixinBiome.java @@ -1,6 +1,6 @@ package net.irisshaders.iris.mixin; -import net.irisshaders.iris.parsing.ExtendedBiome; +import net.irisshaders.iris.mixinterface.ExtendedBiome; import net.minecraft.world.level.biome.Biome; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinBiomeAmbientSoundsHandler.java b/src/main/java/net/irisshaders/iris/mixin/MixinBiomeAmbientSoundsHandler.java new file mode 100644 index 0000000000..bc6947d762 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixin/MixinBiomeAmbientSoundsHandler.java @@ -0,0 +1,46 @@ +package net.irisshaders.iris.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.mixinterface.BiomeAmbienceInterface; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.AmbientMoodSettings; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BiomeAmbientSoundsHandler.class) +public class MixinBiomeAmbientSoundsHandler implements BiomeAmbienceInterface { + @Shadow + @Final + private LocalPlayer player; + + @Unique + private float constantMoodiness; + + @Inject(method = "method_26271", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getBrightness(Lnet/minecraft/world/level/LightLayer;Lnet/minecraft/core/BlockPos;)I", ordinal = 0)) + private void calculateConstantMoodiness(AmbientMoodSettings ambientMoodSettings, CallbackInfo ci, @Local BlockPos blockPos) { + int j = this.player.level().getBrightness(LightLayer.SKY, blockPos); + if (j > 0) { + this.constantMoodiness -= (float)j / (float)this.player.level().getMaxLightLevel() * 0.001F; + } else { + this.constantMoodiness -= (float)(this.player.level().getBrightness(LightLayer.BLOCK, blockPos) - 1) / (float)ambientMoodSettings.getTickDelay(); + } + + this.constantMoodiness = Mth.clamp(constantMoodiness, 0.0f, 1.0f); + } + + @Override + public float getConstantMood() { + return constantMoodiness; + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinLevelRenderer_SkipRendering.java b/src/main/java/net/irisshaders/iris/mixin/MixinLevelRenderer_SkipRendering.java new file mode 100644 index 0000000000..16cced5675 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixin/MixinLevelRenderer_SkipRendering.java @@ -0,0 +1,84 @@ +package net.irisshaders.iris.mixin; + +import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.pipeline.IrisRenderingPipeline; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Collections; +import java.util.Set; + +@Mixin(LevelRenderer.class) +public class MixinLevelRenderer_SkipRendering { + @Shadow + @Final + private ObjectArrayList visibleSections; + @Shadow + @Final + private Set globalBlockEntities; + @Unique + private static final ObjectArrayList EMPTY_LIST = new ObjectArrayList<>(); + + @WrapWithCondition(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;setupRender(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/culling/Frustum;ZZ)V")) + private boolean skipSetupRender(LevelRenderer instance, Camera camera, Frustum frustum, boolean bl, boolean bl2) { + if (Iris.getPipelineManager().getPipelineNullable() instanceof IrisRenderingPipeline pipeline) { + return !pipeline.skipAllRendering(); + } else { + return true; + } + } + + @WrapWithCondition(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V")) + private boolean skipRenderChunks(LevelRenderer instance, RenderType renderType, PoseStack poseStack, double d, double e, double f, Matrix4f matrix4f) { + if (Iris.getPipelineManager().getPipelineNullable() instanceof IrisRenderingPipeline pipeline) { + return !pipeline.skipAllRendering(); + } else { + return true; + } + } + + @WrapOperation(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;entitiesForRendering()Ljava/lang/Iterable;")) + private Iterable skipRenderEntities(ClientLevel instance, Operation> original) { + if (Iris.getPipelineManager().getPipelineNullable() instanceof IrisRenderingPipeline pipeline && pipeline.skipAllRendering()) { + return Collections.emptyList(); + } else { + return original.call(instance); + } + } + + @WrapOperation(method = "renderLevel", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/LevelRenderer;visibleSections:Lit/unimi/dsi/fastutil/objects/ObjectArrayList;")) + private ObjectArrayList skipLocalBlockEntities(LevelRenderer instance, Operation> original) { + if (Iris.getPipelineManager().getPipelineNullable() instanceof IrisRenderingPipeline pipeline && pipeline.skipAllRendering()) { + return EMPTY_LIST; + } else { + return original.call(instance); + } + } + + @WrapOperation(method = "renderLevel", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/LevelRenderer;globalBlockEntities:Ljava/util/Set;")) + private Set skipGlobalBlockEntities(LevelRenderer instance, Operation> original) { + if (Iris.getPipelineManager().getPipelineNullable() instanceof IrisRenderingPipeline pipeline && pipeline.skipAllRendering()) { + return Collections.emptySet(); + } else { + return original.call(instance); + } + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinLocalPlayer.java b/src/main/java/net/irisshaders/iris/mixin/MixinLocalPlayer.java new file mode 100644 index 0000000000..fa96ecfc85 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixin/MixinLocalPlayer.java @@ -0,0 +1,30 @@ +package net.irisshaders.iris.mixin; + +import net.irisshaders.iris.mixinterface.BiomeAmbienceInterface; +import net.irisshaders.iris.mixinterface.LocalPlayerInterface; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.sounds.AmbientSoundHandler; +import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(LocalPlayer.class) +public class MixinLocalPlayer implements LocalPlayerInterface { + @Shadow + @Final + private List ambientSoundHandlers; + + @Override + public float getCurrentConstantMood() { + for(AmbientSoundHandler ambientSoundHandler : this.ambientSoundHandlers) { + if (ambientSoundHandler instanceof BiomeAmbientSoundsHandler) { + return ((BiomeAmbienceInterface)ambientSoundHandler).getConstantMood(); + } + } + + return 0.0F; + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinProgram.java b/src/main/java/net/irisshaders/iris/mixin/MixinProgram.java index 3facc26d0c..4436137bbb 100644 --- a/src/main/java/net/irisshaders/iris/mixin/MixinProgram.java +++ b/src/main/java/net/irisshaders/iris/mixin/MixinProgram.java @@ -30,7 +30,7 @@ public class MixinProgram { return includeHandler.process(shaderSource); } - @Inject(method = "compileShaderInternal", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;glGetShaderInfoLog(II)Ljava/lang/String;"), locals = LocalCapture.CAPTURE_FAILHARD) + @Inject(method = "compileShaderInternal", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;glGetShaderInfoLog(II)Ljava/lang/String;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) private static void iris$causeException(Program.Type arg, String string, InputStream inputStream, String string2, GlslPreprocessor arg2, CallbackInfoReturnable cir, String string3, int i) { cir.cancel(); throw new ShaderCompileException(string + arg.getExtension(), GlStateManager.glGetShaderInfoLog(i, 32768)); diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinQuickPlayDev.java b/src/main/java/net/irisshaders/iris/mixin/MixinQuickPlayDev.java new file mode 100644 index 0000000000..761e7d394f --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixin/MixinQuickPlayDev.java @@ -0,0 +1,37 @@ +package net.irisshaders.iris.mixin; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.DisconnectedScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; +import net.minecraft.client.quickplay.QuickPlay; +import net.minecraft.world.Difficulty; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.WorldDataConfiguration; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.presets.WorldPresets; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(QuickPlay.class) +public class MixinQuickPlayDev { + @Inject(method = "joinSingleplayerWorld", at = @At("HEAD"), cancellable = true) + private static void iris$createWorldIfDev(Minecraft minecraft, String string, CallbackInfo ci) { + if (FabricLoader.getInstance().isDevelopmentEnvironment()) { + ci.cancel(); + + if (!minecraft.getLevelSource().levelExists(string)) { + minecraft.createWorldOpenFlows().createFreshLevel(string, new LevelSettings(string, GameType.CREATIVE, false, Difficulty.HARD, true, new GameRules(), WorldDataConfiguration.DEFAULT), + WorldOptions.defaultWithRandomSeed(), WorldPresets::createNormalWorldDimensions, Minecraft.getInstance().screen); + } else { + minecraft.createWorldOpenFlows().checkForBackupAndLoad(string, () -> minecraft.setScreen(new TitleScreen())); + } + } + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/MixinShaderInstance.java b/src/main/java/net/irisshaders/iris/mixin/MixinShaderInstance.java index 5cdf73a396..41d331852f 100644 --- a/src/main/java/net/irisshaders/iris/mixin/MixinShaderInstance.java +++ b/src/main/java/net/irisshaders/iris/mixin/MixinShaderInstance.java @@ -9,7 +9,7 @@ import net.irisshaders.iris.pipeline.WorldRenderingPipeline; import net.irisshaders.iris.pipeline.programs.ExtendedShader; import net.irisshaders.iris.pipeline.programs.FallbackShader; -import net.irisshaders.iris.pipeline.programs.ShaderInstanceInterface; +import net.irisshaders.iris.mixinterface.ShaderInstanceInterface; import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.server.packs.resources.ResourceProvider; import org.slf4j.Logger; diff --git a/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinBlockEntityRenderDispatcher.java b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinBlockEntityRenderDispatcher.java index 66f2f6ab13..50106ee21b 100644 --- a/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinBlockEntityRenderDispatcher.java +++ b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinBlockEntityRenderDispatcher.java @@ -1,13 +1,19 @@ package net.irisshaders.iris.mixin.entity_render_context; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.irisshaders.batchedentityrendering.impl.Groupable; +import net.irisshaders.batchedentityrendering.impl.wrappers.TaggingRenderTypeWrapper; +import net.irisshaders.iris.Iris; import net.irisshaders.iris.layer.BlockEntityRenderStateShard; +import net.irisshaders.iris.layer.BufferSourceWrapper; import net.irisshaders.iris.layer.OuterWrappedRenderType; import net.irisshaders.iris.shaderpack.materialmap.WorldRenderingSettings; import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -39,11 +45,6 @@ public class MixinBlockEntityRenderDispatcher { target = "Lnet/minecraft/world/level/block/entity/BlockEntityType;isValid(Lnet/minecraft/world/level/block/state/BlockState;)Z"), allow = 1, require = 1, argsOnly = true) private MultiBufferSource iris$wrapBufferSource(MultiBufferSource bufferSource, BlockEntity blockEntity) { - if (!(bufferSource instanceof Groupable)) { - // Fully batched entity rendering is not being used, do not use this wrapper!!! - return bufferSource; - } - BlockState state = blockEntity.getBlockState(); Object2IntMap blockStateIds = WorldRenderingSettings.INSTANCE.getBlockStateIds(); @@ -56,8 +57,7 @@ public class MixinBlockEntityRenderDispatcher { CapturedRenderingState.INSTANCE.setCurrentBlockEntity(intId); - return type -> - bufferSource.getBuffer(OuterWrappedRenderType.wrapExactlyOnce("iris:is_block_entity", type, BlockEntityRenderStateShard.INSTANCE)); + return new BufferSourceWrapper(bufferSource, (renderType) -> OuterWrappedRenderType.wrapExactlyOnce("iris:block_entity", renderType, BlockEntityRenderStateShard.INSTANCE)); } diff --git a/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEnderDragonRenderer.java b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEnderDragonRenderer.java new file mode 100644 index 0000000000..4965a80713 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEnderDragonRenderer.java @@ -0,0 +1,39 @@ +package net.irisshaders.iris.mixin.entity_render_context; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.irisshaders.iris.shaderpack.materialmap.NamespacedId; +import net.irisshaders.iris.shaderpack.materialmap.WorldRenderingSettings; +import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EnderDragonRenderer; +import net.minecraft.client.renderer.entity.layers.CapeLayer; +import net.minecraft.client.resources.PlayerSkin; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(EnderDragonRenderer.class) +public class MixinEnderDragonRenderer { + private static final NamespacedId END_BEAM = new NamespacedId("minecraft", "end_crystal_beam"); + private static int previousE; + + @Inject(method = "renderCrystalBeams", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V")) + private static void changeId(float f, float g, float h, float i, int j, PoseStack poseStack, MultiBufferSource multiBufferSource, int k, CallbackInfo ci) { + if (WorldRenderingSettings.INSTANCE.getEntityIds() == null) return; + + previousE = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity(); + CapturedRenderingState.INSTANCE.setCurrentEntity(WorldRenderingSettings.INSTANCE.getEntityIds().applyAsInt(END_BEAM)); + } + + @Inject(method = "renderCrystalBeams", at = @At(value = "RETURN")) + private static void changeId2(CallbackInfo ci) { + if (previousE != 0) { + CapturedRenderingState.INSTANCE.setCurrentEntity(previousE); + previousE = 0; + } + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java index dfa51953a9..35e3e85ff8 100644 --- a/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java +++ b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java @@ -3,6 +3,8 @@ import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.Object2IntFunction; import net.irisshaders.batchedentityrendering.impl.Groupable; +import net.irisshaders.iris.layer.BlockEntityRenderStateShard; +import net.irisshaders.iris.layer.BufferSourceWrapper; import net.irisshaders.iris.layer.EntityRenderStateShard; import net.irisshaders.iris.layer.OuterWrappedRenderType; import net.irisshaders.iris.shaderpack.materialmap.NamespacedId; @@ -29,13 +31,8 @@ public class MixinEntityRenderDispatcher { // Inject after MatrixStack#push since at this point we know that most cancellation checks have already passed. @ModifyVariable(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V", shift = At.Shift.AFTER), - allow = 1, require = 1) + allow = 1, require = 1, argsOnly = true) private MultiBufferSource iris$beginEntityRender(MultiBufferSource bufferSource, Entity entity) { - if (!(bufferSource instanceof Groupable)) { - // Fully batched entity rendering is not being used, do not use this wrapper!!! - return bufferSource; - } - Object2IntFunction entityIds = WorldRenderingSettings.INSTANCE.getEntityIds(); if (entityIds == null) { @@ -53,8 +50,7 @@ public class MixinEntityRenderDispatcher { CapturedRenderingState.INSTANCE.setCurrentEntity(intId); - return type -> - bufferSource.getBuffer(OuterWrappedRenderType.wrapExactlyOnce("iris:is_entity", type, EntityRenderStateShard.INSTANCE)); + return new BufferSourceWrapper(bufferSource, (renderType) -> OuterWrappedRenderType.wrapExactlyOnce("iris:entity", renderType, EntityRenderStateShard.INSTANCE)); } // Inject before MatrixStack#pop so that our wrapper stack management operations naturally line up diff --git a/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderer.java b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderer.java new file mode 100644 index 0000000000..15da2555d7 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderer.java @@ -0,0 +1,48 @@ +package net.irisshaders.iris.mixin.entity_render_context; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.objects.Object2IntFunction; +import net.irisshaders.iris.shaderpack.materialmap.NamespacedId; +import net.irisshaders.iris.shaderpack.materialmap.WorldRenderingSettings; +import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderer.class) +public class MixinEntityRenderer { + @Unique + private static final NamespacedId NAME_TAG_ID = new NamespacedId("minecraft", "name_tag"); + + @Unique + private int lastId = -100; + + @Inject(method = "renderNameTag", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getNameTagOffsetY()F")) + private void setNameTagId(T entity, Component component, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, CallbackInfo ci) { + Object2IntFunction entityIds = WorldRenderingSettings.INSTANCE.getEntityIds(); + + if (entityIds == null) { + return; + } + + this.lastId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity(); + + int intId = entityIds.applyAsInt(NAME_TAG_ID); + + CapturedRenderingState.INSTANCE.setCurrentEntity(intId); + } + + @Inject(method = "renderNameTag", at = @At("RETURN")) + private void resetId(T entity, Component component, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, CallbackInfo ci) { + if (lastId != -100) { + CapturedRenderingState.INSTANCE.setCurrentEntity(lastId); + lastId = -100 ; + } + } +} diff --git a/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java b/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java index c145f81d80..827eabc51c 100644 --- a/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java +++ b/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java @@ -48,7 +48,7 @@ public abstract class MixinBufferBuilder extends DefaultedVertexConsumer impleme @Unique private boolean injectNormalAndUV1; @Unique - private int vertexCount; + private int iris$vertexCount; @Unique private short currentBlock = -1; @Unique @@ -127,7 +127,7 @@ public abstract class MixinBufferBuilder extends DefaultedVertexConsumer impleme @Inject(method = "reset()V", at = @At("HEAD")) private void iris$onReset(CallbackInfo ci) { - vertexCount = 0; + iris$vertexCount = 0; } @Inject(method = "endVertex", at = @At("HEAD")) @@ -171,16 +171,16 @@ public abstract class MixinBufferBuilder extends DefaultedVertexConsumer impleme this.nextElement(); } - vertexCount++; + iris$vertexCount++; - if (mode == VertexFormat.Mode.QUADS && vertexCount == 4 || mode == VertexFormat.Mode.TRIANGLES && vertexCount == 3) { - fillExtendedData(vertexCount); + if (mode == VertexFormat.Mode.QUADS && iris$vertexCount == 4 || mode == VertexFormat.Mode.TRIANGLES && iris$vertexCount == 3) { + fillExtendedData(iris$vertexCount); } } @Unique private void fillExtendedData(int vertexAmount) { - vertexCount = 0; + iris$vertexCount = 0; int stride = format.getVertexSize(); @@ -289,17 +289,17 @@ public void endBlock() { @Override public int iris$vertexCount() { - return vertexCount; + return iris$vertexCount; } @Override public void iris$incrementVertexCount() { - vertexCount++; + iris$vertexCount++; } @Override public void iris$resetVertexCount() { - vertexCount = 0; + iris$vertexCount = 0; } @Override diff --git a/src/main/java/net/irisshaders/iris/mixinterface/BiomeAmbienceInterface.java b/src/main/java/net/irisshaders/iris/mixinterface/BiomeAmbienceInterface.java new file mode 100644 index 0000000000..359ce169e6 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixinterface/BiomeAmbienceInterface.java @@ -0,0 +1,5 @@ +package net.irisshaders.iris.mixinterface; + +public interface BiomeAmbienceInterface { + float getConstantMood(); +} diff --git a/src/main/java/net/irisshaders/iris/parsing/ExtendedBiome.java b/src/main/java/net/irisshaders/iris/mixinterface/ExtendedBiome.java similarity index 74% rename from src/main/java/net/irisshaders/iris/parsing/ExtendedBiome.java rename to src/main/java/net/irisshaders/iris/mixinterface/ExtendedBiome.java index c441b93aa9..f9a22b1ecc 100644 --- a/src/main/java/net/irisshaders/iris/parsing/ExtendedBiome.java +++ b/src/main/java/net/irisshaders/iris/mixinterface/ExtendedBiome.java @@ -1,4 +1,4 @@ -package net.irisshaders.iris.parsing; +package net.irisshaders.iris.mixinterface; public interface ExtendedBiome { int getBiomeCategory(); diff --git a/src/main/java/net/irisshaders/iris/mixinterface/LocalPlayerInterface.java b/src/main/java/net/irisshaders/iris/mixinterface/LocalPlayerInterface.java new file mode 100644 index 0000000000..8ddcd4a3be --- /dev/null +++ b/src/main/java/net/irisshaders/iris/mixinterface/LocalPlayerInterface.java @@ -0,0 +1,5 @@ +package net.irisshaders.iris.mixinterface; + +public interface LocalPlayerInterface { + float getCurrentConstantMood(); +} diff --git a/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderInstanceInterface.java b/src/main/java/net/irisshaders/iris/mixinterface/ShaderInstanceInterface.java similarity index 82% rename from src/main/java/net/irisshaders/iris/pipeline/programs/ShaderInstanceInterface.java rename to src/main/java/net/irisshaders/iris/mixinterface/ShaderInstanceInterface.java index de0c7a0003..e5dc7145d6 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderInstanceInterface.java +++ b/src/main/java/net/irisshaders/iris/mixinterface/ShaderInstanceInterface.java @@ -1,4 +1,4 @@ -package net.irisshaders.iris.pipeline.programs; +package net.irisshaders.iris.mixinterface; import net.minecraft.server.packs.resources.ResourceProvider; diff --git a/src/main/java/net/irisshaders/iris/parsing/IrisFunctions.java b/src/main/java/net/irisshaders/iris/parsing/IrisFunctions.java index 380ab557c5..9dcb6317fd 100644 --- a/src/main/java/net/irisshaders/iris/parsing/IrisFunctions.java +++ b/src/main/java/net/irisshaders/iris/parsing/IrisFunctions.java @@ -23,6 +23,7 @@ import kroppeb.stareval.function.TypedFunction.Parameter; import kroppeb.stareval.function.V2FFunction; import kroppeb.stareval.function.V2IFunction; +import net.irisshaders.iris.Iris; import org.joml.Matrix4f; import org.joml.Vector2f; import org.joml.Vector2i; @@ -493,20 +494,6 @@ public void evaluateTo(Expression[] params, FunctionContext context, FunctionRet } }); } - - for (Type type : VectorType.AllVectorTypes) { - add("if", new AbstractTypedFunction(type, new Type[]{Type.Boolean, type, type}) { - @Override - public void evaluateTo(Expression[] params, FunctionContext context, FunctionReturn functionReturn) { - params[0].evaluateTo(context, functionReturn); - - params[ - functionReturn.booleanReturn ? 1 : 2 - ].evaluateTo(context, functionReturn); - - } - }); - } } } } diff --git a/src/main/java/net/irisshaders/iris/pipeline/FinalPassRenderer.java b/src/main/java/net/irisshaders/iris/pipeline/FinalPassRenderer.java index b902497f88..6a4d9dfb01 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/FinalPassRenderer.java +++ b/src/main/java/net/irisshaders/iris/pipeline/FinalPassRenderer.java @@ -29,6 +29,7 @@ import net.irisshaders.iris.samplers.IrisImages; import net.irisshaders.iris.samplers.IrisSamplers; import net.irisshaders.iris.shaderpack.FilledIndirectPointer; +import net.irisshaders.iris.shaderpack.loading.ProgramId; import net.irisshaders.iris.shaderpack.programs.ComputeSource; import net.irisshaders.iris.shaderpack.programs.ProgramSet; import net.irisshaders.iris.shaderpack.programs.ProgramSource; @@ -96,7 +97,7 @@ public FinalPassRenderer(WorldRenderingPipeline pipeline, ProgramSet pack, Rende this.noiseTexture = noiseTexture; this.renderTargets = renderTargets; this.customUniforms = customUniforms; - this.finalPass = pack.getCompositeFinal().map(source -> { + this.finalPass = pack.get(ProgramId.Final).map(source -> { Pass pass = new Pass(); ProgramDirectives directives = source.getDirectives(); diff --git a/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java b/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java index ab442a8395..627cec6b83 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java +++ b/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java @@ -53,6 +53,7 @@ import net.irisshaders.iris.shaderpack.FilledIndirectPointer; import net.irisshaders.iris.shaderpack.ImageInformation; import net.irisshaders.iris.shaderpack.ShaderPack; +import net.irisshaders.iris.shaderpack.loading.ProgramArrayId; import net.irisshaders.iris.shaderpack.loading.ProgramId; import net.irisshaders.iris.shaderpack.materialmap.BlockMaterialMapping; import net.irisshaders.iris.shaderpack.materialmap.WorldRenderingSettings; @@ -165,6 +166,8 @@ public class IrisRenderingPipeline implements WorldRenderingPipeline, ShaderRend private final PackShadowDirectives shadowDirectives; private final DHCompat dhCompat; private final int stackSize = 0; + private final boolean skipAllRendering; + private boolean initializedBlockIds; public boolean isBeforeTranslucent; private ShaderStorageBufferHolder shaderStorageBufferHolder; private ShadowRenderTargets shadowRenderTargets; @@ -198,6 +201,7 @@ public IrisRenderingPipeline(ProgramSet programSet) { this.shouldRenderSun = programSet.getPackDirectives().shouldRenderSun(); this.shouldRenderMoon = programSet.getPackDirectives().shouldRenderMoon(); this.allowConcurrentCompute = programSet.getPackDirectives().getConcurrentCompute(); + this.skipAllRendering = programSet.getPackDirectives().skipAllRendering(); this.frustumCulling = programSet.getPackDirectives().shouldUseFrustumCulling(); this.occlusionCulling = programSet.getPackDirectives().shouldUseOcclusionCulling(); this.resolver = new ProgramFallbackResolver(programSet); @@ -234,7 +238,7 @@ public IrisRenderingPipeline(ProgramSet programSet) { this.clearImages = customImages.stream().filter(GlImage::shouldClear).toArray(GlImage[]::new); this.particleRenderingSettings = programSet.getPackDirectives().getParticleRenderingSettings().orElseGet(() -> { - if (programSet.getDeferred().length > 0 && !programSet.getPackDirectives().shouldUseSeparateEntityDraws()) { + if (programSet.getComposite(ProgramArrayId.Deferred).length > 0 && !programSet.getPackDirectives().shouldUseSeparateEntityDraws()) { return ParticleRenderingSettings.AFTER; } else { return ParticleRenderingSettings.MIXED; @@ -285,30 +289,34 @@ public IrisRenderingPipeline(ProgramSet programSet) { return shadowRenderTargets; }; + if (shadowDirectives.isShadowEnabled() == OptionalBoolean.TRUE) { + shadowTargetsSupplier.get(); + } + this.shadowComputes = createShadowComputes(programSet.getShadowCompute(), programSet); - this.beginRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getBegin(), programSet.getBeginCompute(), renderTargets, shaderStorageBufferHolder, + this.beginRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getComposite(ProgramArrayId.Begin), programSet.getCompute(ProgramArrayId.Begin), renderTargets, shaderStorageBufferHolder, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, TextureStage.BEGIN, customTextureManager.getCustomTextureIdMap().getOrDefault(TextureStage.BEGIN, Object2ObjectMaps.emptyMap()), customTextureManager.getIrisCustomTextures(), customImages, programSet.getPackDirectives().getExplicitFlips("begin_pre"), customUniforms); flippedBeforeShadow = flipper.snapshot(); - this.prepareRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getPrepare(), programSet.getPrepareCompute(), renderTargets, shaderStorageBufferHolder, + this.prepareRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getComposite(ProgramArrayId.Prepare), programSet.getCompute(ProgramArrayId.Prepare), renderTargets, shaderStorageBufferHolder, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, TextureStage.PREPARE, customTextureManager.getCustomTextureIdMap().getOrDefault(TextureStage.PREPARE, Object2ObjectMaps.emptyMap()), customTextureManager.getIrisCustomTextures(), customImages, programSet.getPackDirectives().getExplicitFlips("prepare_pre"), customUniforms); flippedAfterPrepare = flipper.snapshot(); - this.deferredRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getDeferred(), programSet.getDeferredCompute(), renderTargets, shaderStorageBufferHolder, + this.deferredRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getComposite(ProgramArrayId.Deferred), programSet.getCompute(ProgramArrayId.Deferred), renderTargets, shaderStorageBufferHolder, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, TextureStage.DEFERRED, customTextureManager.getCustomTextureIdMap().getOrDefault(TextureStage.DEFERRED, Object2ObjectMaps.emptyMap()), customTextureManager.getIrisCustomTextures(), customImages, programSet.getPackDirectives().getExplicitFlips("deferred_pre"), customUniforms); flippedAfterTranslucent = flipper.snapshot(); - this.compositeRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getComposite(), programSet.getCompositeCompute(), renderTargets, shaderStorageBufferHolder, + this.compositeRenderer = new CompositeRenderer(this, programSet.getPackDirectives(), programSet.getComposite(ProgramArrayId.Composite), programSet.getCompute(ProgramArrayId.Composite), renderTargets, shaderStorageBufferHolder, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, TextureStage.COMPOSITE_AND_FINAL, customTextureManager.getCustomTextureIdMap().getOrDefault(TextureStage.COMPOSITE_AND_FINAL, Object2ObjectMaps.emptyMap()), customTextureManager.getIrisCustomTextures(), customImages, programSet.getPackDirectives().getExplicitFlips("composite_pre"), customUniforms); @@ -433,9 +441,7 @@ public IrisRenderingPipeline(ProgramSet programSet) { } }); - WorldRenderingSettings.INSTANCE.setBlockStateIds( - BlockMaterialMapping.createBlockStateIdMap(programSet.getPack().getIdMap().getBlockProperties())); - WorldRenderingSettings.INSTANCE.setBlockTypeIds(BlockMaterialMapping.createBlockTypeMap(programSet.getPack().getIdMap().getBlockRenderTypeMap())); + initializedBlockIds = false; WorldRenderingSettings.INSTANCE.setEntityIds(programSet.getPack().getIdMap().getEntityIdMap()); WorldRenderingSettings.INSTANCE.setItemIds(programSet.getPack().getIdMap().getItemIdMap()); @@ -446,10 +452,6 @@ public IrisRenderingPipeline(ProgramSet programSet) { WorldRenderingSettings.INSTANCE.setSeparateEntityDraws(programSet.getPackDirectives().shouldUseSeparateEntityDraws()); WorldRenderingSettings.INSTANCE.setUseExtendedVertexFormat(true); - if (shadowRenderTargets == null && shadowDirectives.isShadowEnabled() == OptionalBoolean.TRUE) { - shadowRenderTargets = new ShadowRenderTargets(this, shadowMapResolution, shadowDirectives); - } - if (shadowRenderTargets != null) { ShaderInstance shader = shaderMap.getShader(ShaderKey.SHADOW_TERRAIN_CUTOUT); boolean shadowUsesImages = false; @@ -460,11 +462,11 @@ public IrisRenderingPipeline(ProgramSet programSet) { this.shadowClearPasses = ClearPassCreator.createShadowClearPasses(shadowRenderTargets, false, shadowDirectives); this.shadowClearPassesFull = ClearPassCreator.createShadowClearPasses(shadowRenderTargets, true, shadowDirectives); - this.shadowCompositeRenderer = new ShadowCompositeRenderer(this, programSet.getPackDirectives(), programSet.getShadowComposite(), programSet.getShadowCompCompute(), this.shadowRenderTargets, this.shaderStorageBufferHolder, customTextureManager.getNoiseTexture(), updateNotifier, + this.shadowCompositeRenderer = new ShadowCompositeRenderer(this, programSet.getPackDirectives(), programSet.getComposite(ProgramArrayId.ShadowComposite), programSet.getCompute(ProgramArrayId.ShadowComposite), this.shadowRenderTargets, this.shaderStorageBufferHolder, customTextureManager.getNoiseTexture(), updateNotifier, customTextureManager.getCustomTextureIdMap(TextureStage.SHADOWCOMP), customImages, programSet.getPackDirectives().getExplicitFlips("shadowcomp_pre"), customTextureManager.getIrisCustomTextures(), customUniforms); if (programSet.getPackDirectives().getShadowDirectives().isShadowEnabled().orElse(true)) { - this.shadowRenderer = new ShadowRenderer(programSet.getShadow().orElse(null), + this.shadowRenderer = new ShadowRenderer(resolver.resolveNullable(ProgramId.ShadowSolid), programSet.getPackDirectives(), shadowRenderTargets, shadowCompositeRenderer, customUniforms, programSet.getPack().hasFeature(FeatureFlags.SEPARATE_HARDWARE_SAMPLERS)); } else { shadowRenderer = null; @@ -479,9 +481,9 @@ public IrisRenderingPipeline(ProgramSet programSet) { // TODO: Create fallback Sodium shaders if the pack doesn't provide terrain shaders // Currently we use Sodium's shaders but they don't support EXP2 fog underwater. - this.sodiumTerrainPipeline = new SodiumTerrainPipeline(this, programSet, createTerrainSamplers, + this.sodiumTerrainPipeline = new SodiumTerrainPipeline(this, resolver, programSet, createTerrainSamplers, shadowRenderTargets == null ? null : createShadowTerrainSamplers, createTerrainImages, createShadowTerrainImages, renderTargets, flippedAfterPrepare, flippedAfterTranslucent, - shadowRenderTargets != null ? shadowRenderTargets.createShadowFramebuffer(ImmutableSet.of(), programSet.getShadow().filter(source -> !source.getDirectives().hasUnknownDrawBuffers()).map(source -> source.getDirectives().getDrawBuffers()).orElse(new int[]{0, 1})) : null, customUniforms); + shadowRenderTargets != null ? shadowRenderTargets.createShadowFramebuffer(ImmutableSet.of(), resolver.resolve(ProgramId.ShadowSolid).filter(source -> !source.getDirectives().hasUnknownDrawBuffers()).map(source -> source.getDirectives().getDrawBuffers()).orElse(new int[]{0, 1})) : null, customUniforms); this.setup = createSetupComputes(programSet.getSetup(), programSet, TextureStage.SETUP); @@ -846,6 +848,14 @@ public void onSetShaderTexture(int id) { public void beginLevelRendering() { isRenderingWorld = true; + if (!initializedBlockIds) { + WorldRenderingSettings.INSTANCE.setBlockStateIds( + BlockMaterialMapping.createBlockStateIdMap(pack.getIdMap().getBlockProperties(), pack.getIdMap().getTagEntries())); + WorldRenderingSettings.INSTANCE.setBlockTypeIds(BlockMaterialMapping.createBlockTypeMap(pack.getIdMap().getBlockRenderTypeMap())); + Minecraft.getInstance().levelRenderer.allChanged(); + initializedBlockIds = true; + } + // Make sure we're using texture unit 0 for this. RenderSystem.activeTexture(GL15C.GL_TEXTURE0); Vector4f emptyClearColor = new Vector4f(1.0F); @@ -991,7 +1001,7 @@ public void beginLevelRendering() { // A lot of dimension mods touch sky rendering, FabricSkyboxes injects at HEAD and cancels, etc. DimensionSpecialEffects.SkyType skyType = Minecraft.getInstance().level.effects().skyType(); - if (skyType == DimensionSpecialEffects.SkyType.NORMAL) { + if (skyType == DimensionSpecialEffects.SkyType.NORMAL || Minecraft.getInstance().level.dimensionType().hasSkyLight()) { RenderSystem.depthMask(false); RenderSystem.setShaderColor(fogColor.x, fogColor.y, fogColor.z, fogColor.w); @@ -1296,4 +1306,8 @@ public GlFramebuffer createDHFramebufferShadow(ProgramSource sources) { public boolean hasShadowRenderTargets() { return shadowRenderTargets != null; } + + public boolean skipAllRendering() { + return skipAllRendering; + } } diff --git a/src/main/java/net/irisshaders/iris/pipeline/SodiumTerrainPipeline.java b/src/main/java/net/irisshaders/iris/pipeline/SodiumTerrainPipeline.java index 4dfd6daf54..1a5f8f8714 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/SodiumTerrainPipeline.java +++ b/src/main/java/net/irisshaders/iris/pipeline/SodiumTerrainPipeline.java @@ -17,6 +17,7 @@ import net.irisshaders.iris.pipeline.transform.ShaderPrinter; import net.irisshaders.iris.pipeline.transform.TransformPatcher; import net.irisshaders.iris.shaderpack.loading.ProgramId; +import net.irisshaders.iris.shaderpack.programs.ProgramFallbackResolver; import net.irisshaders.iris.shaderpack.programs.ProgramSet; import net.irisshaders.iris.shaderpack.programs.ProgramSource; import net.irisshaders.iris.targets.RenderTargets; @@ -191,6 +192,7 @@ void main() { private final IntFunction createShadowSamplers; private final IntFunction createTerrainImages; private final IntFunction createShadowImages; + private final ProgramFallbackResolver resolver; Optional terrainSolidVertex; Optional terrainSolidGeometry; Optional terrainSolidTessControl; @@ -229,17 +231,18 @@ void main() { Optional shadowAlpha; ProgramSet programSet; - public SodiumTerrainPipeline(WorldRenderingPipeline parent, ProgramSet programSet, IntFunction createTerrainSamplers, + public SodiumTerrainPipeline(WorldRenderingPipeline parent, ProgramFallbackResolver resolver, ProgramSet programSet, IntFunction createTerrainSamplers, IntFunction createShadowSamplers, IntFunction createTerrainImages, IntFunction createShadowImages, RenderTargets targets, ImmutableSet flippedAfterPrepare, ImmutableSet flippedAfterTranslucent, GlFramebuffer shadowFramebuffer, CustomUniforms customUniforms) { this.parent = Objects.requireNonNull(parent); this.customUniforms = customUniforms; + this.resolver = resolver; - Optional terrainSolidSource = first(programSet.getGbuffersTerrainSolid(), programSet.getGbuffersTerrain(), programSet.getGbuffersTexturedLit(), programSet.getGbuffersTextured(), programSet.getGbuffersBasic()); - Optional terrainCutoutSource = first(programSet.getGbuffersTerrainCutout(), programSet.getGbuffersTerrain(), programSet.getGbuffersTexturedLit(), programSet.getGbuffersTextured(), programSet.getGbuffersBasic()); - Optional translucentSource = first(programSet.getGbuffersWater(), terrainCutoutSource); + Optional terrainSolidSource = resolver.resolve(ProgramId.TerrainSolid); + Optional terrainCutoutSource = resolver.resolve(ProgramId.TerrainCutout); + Optional translucentSource = resolver.resolve(ProgramId.Water); this.programSet = programSet; this.shadowFramebuffer = shadowFramebuffer; @@ -300,9 +303,9 @@ public static String parseSodiumImport(String shader) { public void patchShaders(ChunkVertexType vertexType) { ShaderAttributeInputs inputs = new ShaderAttributeInputs(true, true, false, true, true); - Optional terrainSolidSource = first(programSet.getGbuffersTerrainSolid(), programSet.getGbuffersTerrain(), programSet.getGbuffersTexturedLit(), programSet.getGbuffersTextured(), programSet.getGbuffersBasic()); - Optional terrainCutoutSource = first(programSet.getGbuffersTerrainCutout(), programSet.getGbuffersTerrain(), programSet.getGbuffersTexturedLit(), programSet.getGbuffersTextured(), programSet.getGbuffersBasic()); - Optional translucentSource = first(programSet.getGbuffersWater(), terrainCutoutSource); + Optional terrainSolidSource = resolver.resolve(ProgramId.TerrainSolid); + Optional terrainCutoutSource = resolver.resolve(ProgramId.TerrainCutout); + Optional translucentSource = resolver.resolve(ProgramId.Water); terrainSolidSource.ifPresentOrElse(sources -> { @@ -415,7 +418,7 @@ public void patchShaders(ChunkVertexType vertexType) { translucentFragment = Optional.of(defaultFragment); }); - programSet.getShadow().ifPresentOrElse(sources -> { + resolver.resolve(ProgramId.Shadow).ifPresentOrElse(sources -> { shadowBlendOverride = sources.getDirectives().getBlendModeOverride().orElse(ProgramId.Shadow.getBlendModeOverride()); shadowBufferOverrides = new ArrayList<>(); sources.getDirectives().getBufferBlendOverrides().forEach(information -> { diff --git a/src/main/java/net/irisshaders/iris/pipeline/programs/ExtendedShader.java b/src/main/java/net/irisshaders/iris/pipeline/programs/ExtendedShader.java index 8ccb752a34..79e0fdbb3e 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/programs/ExtendedShader.java +++ b/src/main/java/net/irisshaders/iris/pipeline/programs/ExtendedShader.java @@ -21,6 +21,7 @@ import net.irisshaders.iris.gl.sampler.SamplerHolder; import net.irisshaders.iris.gl.texture.TextureType; import net.irisshaders.iris.gl.uniform.DynamicLocationalUniformHolder; +import net.irisshaders.iris.mixinterface.ShaderInstanceInterface; import net.irisshaders.iris.pipeline.IrisRenderingPipeline; import net.irisshaders.iris.samplers.IrisSamplers; import net.irisshaders.iris.uniforms.CapturedRenderingState; diff --git a/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java b/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java index 8b05c9912f..2cd3023273 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java +++ b/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java @@ -44,7 +44,7 @@ public enum ShaderKey { HAND_TRANSLUCENT(ProgramId.HandWater, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.ENTITY, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), HAND_WATER_BRIGHT(ProgramId.HandWater, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.ENTITY, FogMode.PER_VERTEX, LightingModel.FULLBRIGHT), HAND_WATER_DIFFUSE(ProgramId.HandWater, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.ENTITY, FogMode.PER_VERTEX, LightingModel.DIFFUSE_LM), - LIGHTNING(ProgramId.Entities, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR, FogMode.PER_VERTEX, LightingModel.FULLBRIGHT), + LIGHTNING(ProgramId.Lightning, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR, FogMode.PER_VERTEX, LightingModel.FULLBRIGHT), LEASH(ProgramId.Basic, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), TEXT_BG(ProgramId.EntitiesTrans, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), PARTICLES(ProgramId.Particles, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), diff --git a/src/main/java/net/irisshaders/iris/pipeline/transform/TransformPatcher.java b/src/main/java/net/irisshaders/iris/pipeline/transform/TransformPatcher.java index db44524671..d040227fea 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/transform/TransformPatcher.java +++ b/src/main/java/net/irisshaders/iris/pipeline/transform/TransformPatcher.java @@ -16,6 +16,7 @@ import io.github.douira.glsl_transformer.util.LRUCache; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.irisshaders.iris.Iris; +import net.irisshaders.iris.gl.IrisLimits; import net.irisshaders.iris.gl.blending.AlphaTest; import net.irisshaders.iris.gl.shader.ShaderCompileException; import net.irisshaders.iris.gl.state.ShaderAttributeInputs; @@ -31,6 +32,7 @@ import net.irisshaders.iris.pipeline.transform.transformer.CompositeCoreTransformer; import net.irisshaders.iris.pipeline.transform.transformer.CompositeTransformer; import net.irisshaders.iris.pipeline.transform.transformer.DHTransformer; +import net.irisshaders.iris.pipeline.transform.transformer.LayoutTransformer; import net.irisshaders.iris.pipeline.transform.transformer.SodiumCoreTransformer; import net.irisshaders.iris.pipeline.transform.transformer.SodiumTransformer; import net.irisshaders.iris.pipeline.transform.transformer.TextureTransformer; @@ -140,8 +142,8 @@ public TranslationUnit parseTranslationUnit(Root rootInstance, String input) { if (profile == Profile.CORE || version.number >= 150 && profile == null || isLine) { // patch the version number to at least 330 - if (version.number < 330) { - versionStatement.version = Version.GLSL33; + if (version.number < 410) { + versionStatement.version = Version.GLSL41; } switch (parameters.patch) { @@ -164,8 +166,8 @@ public TranslationUnit parseTranslationUnit(Root rootInstance, String input) { } } else { // patch the version number to at least 330 - if (version.number < 330) { - versionStatement.version = Version.GLSL33; + if (version.number < 410) { + versionStatement.version = Version.GLSL41; } versionStatement.profile = Profile.CORE; @@ -196,6 +198,10 @@ public TranslationUnit parseTranslationUnit(Root rootInstance, String input) { // the compatibility transformer does a grouped transformation CompatibilityTransformer.transformGrouped(transformer, trees, parameters); + + if (IrisLimits.VK_CONFORMANCE) { + LayoutTransformer.transformGrouped(transformer, trees, parameters); + } }); transformer.setTokenFilter(parseTokenFilter); } @@ -205,6 +211,8 @@ private static Map transformInternal( Map inputs, Parameters parameters) { try { + // set shader name + parameters.name = name; return transformer.transform(inputs, parameters); } catch (TransformationException | ParsingException | IllegalStateException | IllegalArgumentException e) { // print the offending programs and rethrow to stop the loading process diff --git a/src/main/java/net/irisshaders/iris/pipeline/transform/parameter/Parameters.java b/src/main/java/net/irisshaders/iris/pipeline/transform/parameter/Parameters.java index 16e1117506..1867eb4801 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/transform/parameter/Parameters.java +++ b/src/main/java/net/irisshaders/iris/pipeline/transform/parameter/Parameters.java @@ -15,6 +15,9 @@ public abstract class Parameters implements JobParameters { public PatchShaderType type; // may only be set by TransformPatcher // WARNING: adding new fields requires updating hashCode and equals methods! + // name of the shader, this should not be part of hash/equals + public String name; // set by TransformPatcher + public Parameters(Patch patch, Object2ObjectMap, String> textureMap) { this.patch = patch; this.textureMap = textureMap; diff --git a/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CommonTransformer.java b/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CommonTransformer.java index e9e294f358..b7b1aad6d4 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CommonTransformer.java +++ b/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CommonTransformer.java @@ -174,8 +174,6 @@ public static void transform( // TODO: Find a way to properly support gl_FragColor, see TransformPatcherOld // which implements this if (root.identifierIndex.has("gl_FragColor")) { - Iris.logger.warn( - "[Patcher] gl_FragColor is not supported yet, please use gl_FragData! Assuming that the shaderpack author intended to use gl_FragData[0]..."); root.replaceReferenceExpressions(t, "gl_FragColor", "gl_FragData[0]"); } diff --git a/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CompatibilityTransformer.java b/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CompatibilityTransformer.java index 86d8f4a23e..96571e566f 100644 --- a/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CompatibilityTransformer.java +++ b/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CompatibilityTransformer.java @@ -472,7 +472,7 @@ public static void transformGrouped( if (inTypeSpecifier == null) { LOGGER.warn( - "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + "The in declaration '" + name + "' in the " + parameters.name + " " + currentType.glShaderType.name() + " shader that has a missing corresponding out declaration in the previous stage " + prevType.name() + " has a non-numeric type and could not be compatibility-patched. See debugging.md for more information."); @@ -497,7 +497,7 @@ public static void transformGrouped( outDeclarations.put(name, null); LOGGER.warn( - "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + "The in declaration '" + name + "' in the " + parameters.name + " " + currentType.glShaderType.name() + " shader is missing a corresponding out declaration in the previous stage " + prevType.name() + " and has been compatibility-patched. See debugging.md for more information."); @@ -523,7 +523,7 @@ public static void transformGrouped( // declaration is not if (outTypeSpecifier.getArraySpecifier() != null) { LOGGER.warn( - "The out declaration '" + name + "' in the " + prevPatchTypes.glShaderType.name() + "The out declaration '" + name + "' in the " + parameters.name + " " + prevPatchTypes.glShaderType.name() + " shader that has a missing corresponding in declaration in the next stage " + type.name() + " has an array type and could not be compatibility-patched. See debugging.md for more information."); @@ -543,7 +543,7 @@ public static void transformGrouped( outDeclarations.put(name, null); LOGGER.warn( - "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + "The in declaration '" + name + "' in the " + parameters.name + " " + currentType.glShaderType.name() + " shader that is never assigned to in the previous stage " + prevType.name() + " has been compatibility-patched by adding an initialization for it. See debugging.md for more information."); @@ -553,7 +553,7 @@ public static void transformGrouped( // bail and warn on mismatching dimensionality if (outType.getDimension() != inType.getDimension()) { LOGGER.warn( - "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + "The in declaration '" + name + "' in the " + parameters.name + " " + currentType.glShaderType.name() + " shader has a mismatching dimensionality (scalar/vector/matrix) with the out declaration in the previous stage " + prevType.name() + " and could not be compatibility-patched. See debugging.md for more information."); @@ -619,7 +619,7 @@ public static void transformGrouped( outDeclarations.put(name, null); LOGGER.warn( - "The out declaration '" + name + "' in the " + prevType.name() + "The out declaration '" + name + "' in the " + parameters.name + " " + prevType.name() + " shader has a different type " + outType.getMostCompactName() + " than the corresponding in declaration of type " + inType.getMostCompactName() + " in the following stage " + currentType.glShaderType.name() diff --git a/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/LayoutTransformer.java b/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/LayoutTransformer.java new file mode 100644 index 0000000000..5431a83e91 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/LayoutTransformer.java @@ -0,0 +1,404 @@ +package net.irisshaders.iris.pipeline.transform.transformer; + +import io.github.douira.glsl_transformer.ast.node.Identifier; +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.abstract_node.ASTNode; +import io.github.douira.glsl_transformer.ast.node.declaration.DeclarationMember; +import io.github.douira.glsl_transformer.ast.node.declaration.FunctionParameter; +import io.github.douira.glsl_transformer.ast.node.declaration.TypeAndInitDeclaration; +import io.github.douira.glsl_transformer.ast.node.expression.Expression; +import io.github.douira.glsl_transformer.ast.node.expression.LiteralExpression; +import io.github.douira.glsl_transformer.ast.node.expression.ReferenceExpression; +import io.github.douira.glsl_transformer.ast.node.expression.unary.FunctionCallExpression; +import io.github.douira.glsl_transformer.ast.node.external_declaration.DeclarationExternalDeclaration; +import io.github.douira.glsl_transformer.ast.node.external_declaration.EmptyDeclaration; +import io.github.douira.glsl_transformer.ast.node.external_declaration.ExternalDeclaration; +import io.github.douira.glsl_transformer.ast.node.external_declaration.FunctionDefinition; +import io.github.douira.glsl_transformer.ast.node.statement.Statement; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.LayoutQualifier; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.NamedLayoutQualifierPart; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.StorageQualifier; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.StorageQualifier.StorageType; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.TypeQualifier; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.TypeQualifierPart; +import io.github.douira.glsl_transformer.ast.node.type.specifier.ArraySpecifier; +import io.github.douira.glsl_transformer.ast.node.type.specifier.BuiltinNumericTypeSpecifier; +import io.github.douira.glsl_transformer.ast.node.type.specifier.FunctionPrototype; +import io.github.douira.glsl_transformer.ast.node.type.specifier.TypeSpecifier; +import io.github.douira.glsl_transformer.ast.node.type.struct.StructDeclarator; +import io.github.douira.glsl_transformer.ast.node.type.struct.StructMember; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.query.match.AutoHintedMatcher; +import io.github.douira.glsl_transformer.ast.query.match.Matcher; +import io.github.douira.glsl_transformer.ast.transform.ASTInjectionPoint; +import io.github.douira.glsl_transformer.ast.transform.ASTParser; +import io.github.douira.glsl_transformer.ast.transform.Template; +import io.github.douira.glsl_transformer.ast.transform.TransformationException; +import io.github.douira.glsl_transformer.parser.ParseShape; +import io.github.douira.glsl_transformer.util.Type; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.gl.shader.ShaderType; +import net.irisshaders.iris.pipeline.transform.PatchShaderType; +import net.irisshaders.iris.pipeline.transform.parameter.Parameters; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class LayoutTransformer { + private static final Logger LOGGER = LogManager.getLogger(LayoutTransformer.class); + + private static final ShaderType[] pipeline = {ShaderType.VERTEX, ShaderType.TESSELATION_CONTROL, ShaderType.TESSELATION_EVAL, ShaderType.GEOMETRY, ShaderType.FRAGMENT}; + private static final Matcher outDeclarationMatcher = new DeclarationMatcher( + StorageType.OUT); + private static final Matcher inDeclarationMatcher = new DeclarationMatcher( + StorageType.IN); + private static final Matcher nonLayoutOutDeclarationMatcher = new Matcher<>( + "out float name;", + ParseShape.EXTERNAL_DECLARATION) { + { + markClassWildcard("qualifier", pattern.getRoot().nodeIndex.getUnique(TypeQualifier.class)); + markClassWildcard("type", pattern.getRoot().nodeIndex.getUnique(BuiltinNumericTypeSpecifier.class)); + markClassWildcard("name*", + pattern.getRoot().identifierIndex.getUnique("name").getAncestor(DeclarationMember.class)); + } + + @Override + public boolean matchesExtract(ExternalDeclaration tree) { + boolean result = super.matchesExtract(tree); + if (!result) { + return false; + } + + // look for an out qualifier but no layout qualifier + TypeQualifier qualifier = getNodeMatch("qualifier", TypeQualifier.class); + var hasOutQualifier = false; + for (TypeQualifierPart part : qualifier.getParts()) { + if (part instanceof StorageQualifier storageQualifier) { + if (storageQualifier.storageType == StorageType.OUT) { + hasOutQualifier = true; + } + } else if (part instanceof LayoutQualifier) { + return false; + } + } + return hasOutQualifier; + } + }; + private static final Matcher nonLayoutInDeclarationMatcher = new Matcher<>( + "in float name;", + ParseShape.EXTERNAL_DECLARATION) { + { + markClassWildcard("qualifier", pattern.getRoot().nodeIndex.getUnique(TypeQualifier.class)); + markClassWildcard("type", pattern.getRoot().nodeIndex.getUnique(BuiltinNumericTypeSpecifier.class)); + markClassWildcard("name*", + pattern.getRoot().identifierIndex.getUnique("name").getAncestor(DeclarationMember.class)); + } + + @Override + public boolean matchesExtract(ExternalDeclaration tree) { + boolean result = super.matchesExtract(tree); + if (!result) { + return false; + } + + // look for an out qualifier but no layout qualifier + TypeQualifier qualifier = getNodeMatch("qualifier", TypeQualifier.class); + var hasOutQualifier = false; + for (TypeQualifierPart part : qualifier.getParts()) { + if (part instanceof StorageQualifier storageQualifier) { + if (storageQualifier.storageType == StorageType.IN) { + hasOutQualifier = true; + } + } else if (part instanceof LayoutQualifier) { + return false; + } + } + return hasOutQualifier; + } + }; + private static final Template layoutedOutDeclarationTemplate = Template + .withExternalDeclaration("out __type __name;"); + private static final Template layoutedInDeclarationTemplate = Template + .withExternalDeclaration("in __type __name;"); + private static final String attachTargetPrefix = "outColor"; + private static final List reservedWords = List.of("texture"); + + static { + layoutedOutDeclarationTemplate.markLocalReplacement( + layoutedOutDeclarationTemplate.getSourceRoot().nodeIndex.getOne(TypeQualifier.class)); + layoutedOutDeclarationTemplate.markLocalReplacement("__type", TypeSpecifier.class); + layoutedOutDeclarationTemplate.markLocalReplacement("__name", DeclarationMember.class); + layoutedInDeclarationTemplate.markLocalReplacement( + layoutedInDeclarationTemplate.getSourceRoot().nodeIndex.getOne(TypeQualifier.class)); + layoutedInDeclarationTemplate.markLocalReplacement("__type", TypeSpecifier.class); + layoutedInDeclarationTemplate.markLocalReplacement("__name", DeclarationMember.class); + } + + private static StorageQualifier getConstQualifier(TypeQualifier qualifier) { + if (qualifier == null) { + return null; + } + for (TypeQualifierPart constQualifier : qualifier.getChildren()) { + if (constQualifier instanceof StorageQualifier storageQualifier) { + if (storageQualifier.storageType == StorageType.CONST) { + return storageQualifier; + } + } + } + return null; + } + + private static TypeQualifier makeQualifierOut(TypeQualifier typeQualifier) { + for (TypeQualifierPart qualifierPart : typeQualifier.getParts()) { + if (qualifierPart instanceof StorageQualifier storageQualifier) { + if (((StorageQualifier) qualifierPart).storageType == StorageType.IN) { + storageQualifier.storageType = StorageType.OUT; + } + } + } + return typeQualifier; + } + + // does transformations that require cross-shader type data + public static void transformGrouped( + ASTParser t, + Map trees, + Parameters parameters) { + /* + find attributes that are declared as "in" in geometry or fragment but not + declared as "out" in the previous stage. The missing "out" declarations for + these attributes are added and initialized. + + It doesn't bother with array specifiers because they are only legal in + geometry shaders, but then also only as an in declaration. The out + declaration in the vertex shader is still just a single value. Missing out + declarations in the geometry shader are also just normal. + + TODO: + - fix issues where Iris' own declarations are detected and patched like + iris_FogFragCoord if there are geometry shaders present + - improved geometry shader support? They use funky declarations + */ + ShaderType prevType = null; + final Object2IntMap[] lastMap = new Object2IntMap[]{null}; + for (ShaderType type : pipeline) { + PatchShaderType[] patchTypes = PatchShaderType.fromGlShaderType(type); + + // check if the patch types have sources and continue if not + boolean hasAny = false; + for (PatchShaderType currentType : patchTypes) { + if (trees.get(currentType) != null) { + hasAny = true; + } + } + + if (!hasAny) { + continue; + } + + + + TranslationUnit currentTree = trees.get(patchTypes[0]); + if (currentTree == null) { + continue; + } + Root currentRoot = currentTree.getRoot(); + + + + currentRoot.indexBuildSession((root) -> { + if (root != null) { + if (lastMap[0] != null) { + transformIn(lastMap[0], t, currentTree, root, parameters); + } + + lastMap[0] = transformOut(t, currentTree, root, parameters); + } + }); + + } + } + + public static Object2IntMap transformOut(ASTParser t, TranslationUnit tree, Root root, Parameters parameters) { + // do layout attachment (attaches a location(layout = 4) to the out declaration + // outColor4 for example) + + // iterate the declarations + ArrayList newDeclarationData = new ArrayList<>(); + int location = 0; + + Object2IntMap map = new Object2IntArrayMap<>(); + ArrayList declarationsToRemove = new ArrayList<>(); + for (DeclarationExternalDeclaration declaration : root.nodeIndex.get(DeclarationExternalDeclaration.class)) { + if (!nonLayoutOutDeclarationMatcher.matchesExtract(declaration)) { + continue; + } + + // find the matching outColor members + List members = nonLayoutOutDeclarationMatcher + .getNodeMatch("name*", DeclarationMember.class) + .getAncestor(TypeAndInitDeclaration.class) + .getMembers(); + TypeQualifier typeQualifier = nonLayoutOutDeclarationMatcher.getNodeMatch("qualifier", TypeQualifier.class); + BuiltinNumericTypeSpecifier typeSpecifier = nonLayoutOutDeclarationMatcher.getNodeMatch("type", + BuiltinNumericTypeSpecifier.class); + int addedDeclarations = 0; + for (DeclarationMember member : members) { + String name = member.getName().getName(); + + map.put(name, location); + + Iris.logger.warn("Found a declaration named " + name); + newDeclarationData.add(new NewDeclarationData(typeQualifier, typeSpecifier, member, location++, name)); + addedDeclarations++; + } + + // if the member list is now empty, remove the declaration + if (addedDeclarations == members.size()) { + declarationsToRemove.add(declaration); + } + } + tree.getChildren().removeAll(declarationsToRemove); + for (ExternalDeclaration declaration : declarationsToRemove) { + declaration.detachParent(); + } + + // generate new declarations with layout qualifiers for each outColor member + ArrayList newDeclarations = new ArrayList<>(); + + // Note: since everything is wrapped in a big Root.indexBuildSession, we don't + // need to do it manually here + for (NewDeclarationData data : newDeclarationData) { + DeclarationMember member = data.member; + member.detach(); + TypeQualifier newQualifier = data.qualifier.cloneInto(root); + newQualifier.getChildren() + .add(0, new LayoutQualifier(Stream.of(new NamedLayoutQualifierPart( + new Identifier("location"), + new LiteralExpression(Type.INT32, data.location))))); + ExternalDeclaration newDeclaration = layoutedOutDeclarationTemplate.getInstanceFor(root, + newQualifier, + data.type.cloneInto(root), + member); + newDeclarations.add(newDeclaration); + } + tree.injectNodes(ASTInjectionPoint.BEFORE_DECLARATIONS, newDeclarations); + + return map; + } + + public static void transformIn(Object2IntMap map, ASTParser t, TranslationUnit tree, Root root, Parameters parameters) { + // do layout attachment (attaches a location(layout = 4) to the out declaration + // outColor4 for example) + + // iterate the declarations + ArrayList newDeclarationData = new ArrayList<>(); + + ArrayList declarationsToRemove = new ArrayList<>(); + for (DeclarationExternalDeclaration declaration : root.nodeIndex.get(DeclarationExternalDeclaration.class)) { + if (!nonLayoutInDeclarationMatcher.matchesExtract(declaration)) { + continue; + } + + // find the matching outColor members + List members = nonLayoutInDeclarationMatcher + .getNodeMatch("name*", DeclarationMember.class) + .getAncestor(TypeAndInitDeclaration.class) + .getMembers(); + TypeQualifier typeQualifier = nonLayoutInDeclarationMatcher.getNodeMatch("qualifier", TypeQualifier.class); + BuiltinNumericTypeSpecifier typeSpecifier = nonLayoutInDeclarationMatcher.getNodeMatch("type", + BuiltinNumericTypeSpecifier.class); + int addedDeclarations = 0; + for (DeclarationMember member : members) { + String name = member.getName().getName(); + Iris.logger.warn("Found a member with name " + name); + + if (!map.containsKey(name)) { + continue; + } + + newDeclarationData.add(new NewDeclarationData(typeQualifier, typeSpecifier, member, map.getInt(name), name)); + addedDeclarations++; + } + + // if the member list is now empty, remove the declaration + if (addedDeclarations == members.size()) { + declarationsToRemove.add(declaration); + } + } + tree.getChildren().removeAll(declarationsToRemove); + for (ExternalDeclaration declaration : declarationsToRemove) { + declaration.detachParent(); + } + + // generate new declarations with layout qualifiers for each outColor member + ArrayList newDeclarations = new ArrayList<>(); + + // Note: since everything is wrapped in a big Root.indexBuildSession, we don't + // need to do it manually here + for (NewDeclarationData data : newDeclarationData) { + DeclarationMember member = data.member; + member.detach(); + TypeQualifier newQualifier = data.qualifier.cloneInto(root); + newQualifier.getChildren() + .add(0, new LayoutQualifier(Stream.of(new NamedLayoutQualifierPart( + new Identifier("location"), + new LiteralExpression(Type.INT32, data.location))))); + ExternalDeclaration newDeclaration = layoutedInDeclarationTemplate.getInstanceFor(root, + newQualifier, + data.type.cloneInto(root), + member); + newDeclarations.add(newDeclaration); + } + tree.injectNodes(ASTInjectionPoint.BEFORE_DECLARATIONS, newDeclarations); + } + + private static class DeclarationMatcher extends Matcher { + private final StorageType storageType; + + { + markClassWildcard("qualifier", pattern.getRoot().nodeIndex.getUnique(TypeQualifier.class)); + markClassWildcard("type", pattern.getRoot().nodeIndex.getUnique(BuiltinNumericTypeSpecifier.class)); + markClassWildcard("name*", + pattern.getRoot().identifierIndex.getUnique("name").getAncestor(DeclarationMember.class)); + } + + public DeclarationMatcher(StorageType storageType) { + super("out float name;", ParseShape.EXTERNAL_DECLARATION); + this.storageType = storageType; + } + + @Override + public boolean matchesExtract(ExternalDeclaration tree) { + boolean result = super.matchesExtract(tree); + if (!result) { + return false; + } + TypeQualifier qualifier = getNodeMatch("qualifier", TypeQualifier.class); + for (TypeQualifierPart part : qualifier.getParts()) { + if (part instanceof StorageQualifier storageQualifier) { + if (storageQualifier.storageType == storageType) { + return true; + } + } + } + return false; + } + } + + record NewDeclarationData(TypeQualifier qualifier, TypeSpecifier type, DeclarationMember member, int location, String name) { + } +} diff --git a/src/main/java/net/irisshaders/iris/shaderpack/IdMap.java b/src/main/java/net/irisshaders/iris/shaderpack/IdMap.java index f410a00f54..bf3ae7f422 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/IdMap.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/IdMap.java @@ -1,8 +1,6 @@ package net.irisshaders.iris.shaderpack; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntFunction; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; @@ -14,8 +12,10 @@ import net.irisshaders.iris.pipeline.transform.ShaderPrinter; import net.irisshaders.iris.shaderpack.materialmap.BlockEntry; import net.irisshaders.iris.shaderpack.materialmap.BlockRenderType; +import net.irisshaders.iris.shaderpack.materialmap.Entry; import net.irisshaders.iris.shaderpack.materialmap.LegacyIdMap; import net.irisshaders.iris.shaderpack.materialmap.NamespacedId; +import net.irisshaders.iris.shaderpack.materialmap.TagEntry; import net.irisshaders.iris.shaderpack.option.OrderBackedProperties; import net.irisshaders.iris.shaderpack.option.ShaderPackOptions; import net.irisshaders.iris.shaderpack.preprocessor.PropertiesPreprocessor; @@ -36,6 +36,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Properties; +import java.util.regex.Matcher; /** * A utility class for parsing entries in item.properties, block.properties, and entities.properties files in shaderpacks @@ -54,7 +55,12 @@ public class IdMap { /** * Maps block states to block ids defined in block.properties */ - private Int2ObjectMap> blockPropertiesMap; + private Int2ObjectLinkedOpenHashMap> blockPropertiesMap; + + /** + * Maps tags to block ids defined in block.properties + */ + private Int2ObjectLinkedOpenHashMap> blockTagMap; /** * A set of render type overrides for specific blocks. Allows shader packs to move blocks to different render types. @@ -67,9 +73,10 @@ public class IdMap { entityIdMap = loadProperties(shaderPath, "entity.properties", shaderPackOptions, environmentDefines) .map(IdMap::parseEntityIdMap).orElse(Object2IntMaps.emptyMap()); + blockTagMap = new Int2ObjectLinkedOpenHashMap<>(); loadProperties(shaderPath, "block.properties", shaderPackOptions, environmentDefines).ifPresent(blockProperties -> { - blockPropertiesMap = parseBlockMap(blockProperties, "block.", "block.properties"); + blockPropertiesMap = parseBlockMap(blockProperties, "block.", "block.properties", blockTagMap); blockRenderTypeMap = parseRenderTypeMap(blockProperties, "layer.", "block.properties"); }); @@ -77,7 +84,7 @@ public class IdMap { if (blockPropertiesMap == null) { // Fill in with default values... - blockPropertiesMap = new Int2ObjectOpenHashMap<>(); + blockPropertiesMap = new Int2ObjectLinkedOpenHashMap<>(); LegacyIdMap.addLegacyValues(blockPropertiesMap); } @@ -98,8 +105,8 @@ private static Optional loadProperties(Path shaderPath, String name, // TODO: This is the worst code I have ever made. Do not do this. String processed = PropertiesPreprocessor.preprocessSource(fileContents, shaderPackOptions, environmentDefines).replaceAll("\\\\\\n\\s*\\n", " ").replaceAll("\\S\s*block\\.", "\nblock."); - StringReader propertiesReader = new StringReader(processed); + warnMissingBackslashInPropertiesFile(processed, name); // Note: ordering of properties is significant // See https://github.com/IrisShaders/Iris/issues/1327 and the relevant putIfAbsent calls in @@ -191,8 +198,9 @@ private static Object2IntMap parseIdMap(Properties properties, Str return Object2IntMaps.unmodifiable(idMap); } - private static Int2ObjectMap> parseBlockMap(Properties properties, String keyPrefix, String fileName) { - Int2ObjectMap> entriesById = new Int2ObjectOpenHashMap<>(); + private static Int2ObjectLinkedOpenHashMap> parseBlockMap(Properties properties, String keyPrefix, String fileName, Int2ObjectLinkedOpenHashMap> blockTagMap) { + Int2ObjectLinkedOpenHashMap> blockEntriesById = new Int2ObjectLinkedOpenHashMap<>(); + Int2ObjectLinkedOpenHashMap> tagEntriesById = new Int2ObjectLinkedOpenHashMap<>(); properties.forEach((keyObject, valueObject) -> { String key = (String) keyObject; @@ -213,7 +221,8 @@ private static Int2ObjectMap> parseBlockMap(Properties properti return; } - List entries = new ArrayList<>(); + List blockEntries = new ArrayList<>(); + List tagEntries = new ArrayList<>(); // Split on whitespace groups, not just single spaces for (String part : value.split("\\s+")) { @@ -222,22 +231,29 @@ private static Int2ObjectMap> parseBlockMap(Properties properti } try { - entries.add(BlockEntry.parse(part)); + Entry entry = BlockEntry.parse(part); + if (entry instanceof BlockEntry be) { + blockEntries.add(be); + } else if (entry instanceof TagEntry te) { + tagEntries.add(te); + } } catch (Exception e) { Iris.logger.warn("Unexpected error while parsing an entry from " + fileName + " for the key " + key + ":", e); } } - entriesById.put(intId, Collections.unmodifiableList(entries)); + blockEntriesById.put(intId, Collections.unmodifiableList(blockEntries)); + tagEntriesById.put(intId, Collections.unmodifiableList(tagEntries)); }); - return Int2ObjectMaps.unmodifiable(entriesById); + blockTagMap.putAll(tagEntriesById); + + return blockEntriesById; } /** * Parses a render layer map. *

- * This feature is used by Chocapic v9 and Wisdom Shaders. Otherwise, it is a rarely-used feature. */ private static Map parseRenderTypeMap(Properties properties, String keyPrefix, String fileName) { Map overrides = new HashMap<>(); @@ -262,6 +278,10 @@ private static Map parseRenderTypeMap(Properties } for (String part : value.split("\\s+")) { + if (part.startsWith("%")) { + Iris.logger.fatal("Cannot use a tag in the render type map: " + key + " = " + value); + continue; + } // Note: NamespacedId performs no validation on the content. That will need to be done by whatever is // converting these things to ResourceLocations. overrides.put(new NamespacedId(part), renderType); @@ -294,10 +314,36 @@ private static Map parseDimensionMap(Properties properties return overrides; } - public Int2ObjectMap> getBlockProperties() { + private static void warnMissingBackslashInPropertiesFile(String processedSource, String propertiesFileName) { + if (propertiesFileName.equals("shaders.properties")) { + return; + } + String[] fileNameSections = propertiesFileName.split("\\."); + String entryName = "entry"; + if (fileNameSections.length >= 2) { + entryName = fileNameSections[0] + " entry"; + } + Matcher matcher = PropertiesPreprocessor.BACKSLASH_MATCHER.matcher(processedSource); + while (matcher.find()) { + Iris.logger.warn("Found missing \"\\\" in file \"{}\" in {}: \"{}\"", propertiesFileName, entryName, matcher.group(0)); + for (int i = 1; i <= matcher.groupCount(); i++) { + String match = matcher.group(i); + if (match == null) { + continue; + } + Iris.logger.warn("At ID: \"{}\"", match); + } + } + } + + public Int2ObjectLinkedOpenHashMap> getBlockProperties() { return blockPropertiesMap; } + public Int2ObjectLinkedOpenHashMap> getTagEntries() { + return blockTagMap; + } + public Object2IntFunction getItemIdMap() { return itemIdMap; } @@ -325,11 +371,12 @@ public boolean equals(Object o) { return Objects.equals(itemIdMap, idMap.itemIdMap) && Objects.equals(entityIdMap, idMap.entityIdMap) && Objects.equals(blockPropertiesMap, idMap.blockPropertiesMap) + && Objects.equals(blockTagMap, idMap.blockTagMap) && Objects.equals(blockRenderTypeMap, idMap.blockRenderTypeMap); } @Override public int hashCode() { - return Objects.hash(itemIdMap, entityIdMap, blockPropertiesMap, blockRenderTypeMap); + return Objects.hash(itemIdMap, entityIdMap, blockPropertiesMap, blockTagMap, blockRenderTypeMap); } } diff --git a/src/main/java/net/irisshaders/iris/shaderpack/IrisDefines.java b/src/main/java/net/irisshaders/iris/shaderpack/IrisDefines.java index 83fc306ee3..9eaa3beaef 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/IrisDefines.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/IrisDefines.java @@ -32,6 +32,10 @@ public static ImmutableList createIrisReplacements() { define(s, "CAT_" + categories[i].name().toUpperCase(Locale.ROOT), String.valueOf(i)); } + define(s, "PPT_NONE", "0"); + define(s, "PPT_RAIN", "1"); + define(s, "PPT_SNOW", "2"); + return ImmutableList.copyOf(s); } } diff --git a/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java b/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java index d4104b73da..426d70d02b 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java @@ -16,6 +16,7 @@ import net.irisshaders.iris.gui.screen.ShaderPackScreen; import net.irisshaders.iris.helpers.StringPair; import net.irisshaders.iris.pathways.colorspace.ColorSpace; +import net.irisshaders.iris.shaderpack.error.RusticError; import net.irisshaders.iris.shaderpack.include.AbsolutePackPath; import net.irisshaders.iris.shaderpack.include.IncludeGraph; import net.irisshaders.iris.shaderpack.include.IncludeProcessor; @@ -27,6 +28,7 @@ import net.irisshaders.iris.shaderpack.option.menu.OptionMenuContainer; import net.irisshaders.iris.shaderpack.option.values.MutableOptionValues; import net.irisshaders.iris.shaderpack.option.values.OptionValues; +import net.irisshaders.iris.shaderpack.parsing.BooleanParser; import net.irisshaders.iris.shaderpack.preprocessor.JcppProcessor; import net.irisshaders.iris.shaderpack.preprocessor.PropertiesPreprocessor; import net.irisshaders.iris.shaderpack.programs.ProgramSet; @@ -150,11 +152,7 @@ public ShaderPack(Path root, Map changedConfigs, ImmutableList { - Iris.logger.error("{}", error.toString()); - }); - - throw new IOException("Failed to resolve some #include directives, see previous messages for details"); + throw new IOException(String.join("\n", graph.getFailures().values().stream().map(RusticError::toString).toArray(String[]::new))); } this.languageMap = new LanguageMap(root.resolve("lang")); @@ -214,7 +212,6 @@ public ShaderPack(Path root, Map changedConfigs, ImmutableList optionalFeatureFlags = shaderProperties.getOptionalFeatureFlags().stream().filter(flag -> !FeatureFlags.isInvalid(flag)).toList(); if (!optionalFeatureFlags.isEmpty()) { - optionalFeatureFlags.forEach(flag -> Iris.logger.warn("Found flag " + flag)); optionalFeatureFlags.forEach(flag -> newEnvDefines.add(new StringPair("IRIS_FEATURE_" + flag, ""))); } @@ -228,9 +225,7 @@ public ShaderPack(Path root, Map changedConfigs, ImmutableList disabledPrograms.addAll(profile.disabledPrograms)); // Add programs that are disabled by shader options shaderProperties.getConditionallyEnabledPrograms().forEach((program, shaderOption) -> { - if ("true".equals(shaderOption)) return; - - if ("false".equals(shaderOption) || !this.shaderPackOptions.getOptionValues().getBooleanValueOrDefault(shaderOption)) { + if (!BooleanParser.parse(shaderOption, this.shaderPackOptions.getOptionValues())) { disabledPrograms.add(program); } }); diff --git a/src/main/java/net/irisshaders/iris/shaderpack/include/FileIncludeException.java b/src/main/java/net/irisshaders/iris/shaderpack/include/FileIncludeException.java new file mode 100644 index 0000000000..0ab3589159 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/shaderpack/include/FileIncludeException.java @@ -0,0 +1,9 @@ +package net.irisshaders.iris.shaderpack.include; + +import java.nio.file.NoSuchFileException; + +public class FileIncludeException extends NoSuchFileException { + public FileIncludeException(String message) { + super(message); + } +} diff --git a/src/main/java/net/irisshaders/iris/shaderpack/include/IncludeGraph.java b/src/main/java/net/irisshaders/iris/shaderpack/include/IncludeGraph.java index aec33ae3e4..76ed7f61d7 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/include/IncludeGraph.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/include/IncludeGraph.java @@ -80,7 +80,12 @@ public IncludeGraph(Path root, ImmutableList startingPaths) { String source; try { - source = readFile(next.resolved(root)); + Path p = next.resolved(root); + if (Iris.getIrisConfig().areDebugOptionsEnabled() && root.isAbsolute() && !p.toAbsolutePath().toString().equals(p.toFile().getCanonicalPath())) { + throw new FileIncludeException("'" + next.getPathString() + "' doesn't exist, did you mean '" + + root.relativize(p.toFile().getCanonicalFile().toPath()).toString().replace("\\", "/") + "'?"); + } + source = readFile(p); } catch (IOException e) { AbsolutePackPath src = cameFrom.get(next); @@ -90,8 +95,10 @@ public IncludeGraph(Path root, ImmutableList startingPaths) { String topLevelMessage; String detailMessage; - - if (e instanceof NoSuchFileException) { + if (e instanceof FileIncludeException) { + topLevelMessage = "failed to resolve #include directive\n" + e.getMessage(); + detailMessage = "file not found"; + } else if (e instanceof NoSuchFileException) { topLevelMessage = "failed to resolve #include directive"; detailMessage = "file not found"; } else { diff --git a/src/main/java/net/irisshaders/iris/shaderpack/loading/ProgramId.java b/src/main/java/net/irisshaders/iris/shaderpack/loading/ProgramId.java index 71651358f6..3fb544bfef 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/loading/ProgramId.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/loading/ProgramId.java @@ -8,9 +8,9 @@ import java.util.Optional; public enum ProgramId { - Shadow(ProgramGroup.Shadow, ""), - ShadowSolid(ProgramGroup.Shadow, "solid", Shadow), - ShadowCutout(ProgramGroup.Shadow, "cutout", Shadow), + Shadow(ProgramGroup.Shadow, "", BlendModeOverride.OFF), + ShadowSolid(ProgramGroup.Shadow, "solid", Shadow, BlendModeOverride.OFF), + ShadowCutout(ProgramGroup.Shadow, "cutout", Shadow, BlendModeOverride.OFF), Basic(ProgramGroup.Gbuffers, "basic"), Line(ProgramGroup.Gbuffers, "line", Basic), @@ -33,6 +33,7 @@ public enum ProgramId { Entities(ProgramGroup.Gbuffers, "entities", TexturedLit), EntitiesTrans(ProgramGroup.Gbuffers, "entities_translucent", Entities), + Lightning(ProgramGroup.Gbuffers, "lightning", Entities), Particles(ProgramGroup.Gbuffers, "particles", TexturedLit), ParticlesTrans(ProgramGroup.Gbuffers, "particles_translucent", Particles), EntitiesGlowing(ProgramGroup.Gbuffers, "entities_glowing", Entities), @@ -63,6 +64,13 @@ public enum ProgramId { this.defaultBlendOverride = null; } + ProgramId(ProgramGroup group, String name, BlendModeOverride defaultBlendOverride) { + this.group = group; + this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name; + this.fallback = null; + this.defaultBlendOverride = defaultBlendOverride; + } + ProgramId(ProgramGroup group, String name, ProgramId fallback) { this.group = group; this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name; diff --git a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockEntry.java b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockEntry.java index d2114a0247..6f929cc088 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockEntry.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockEntry.java @@ -7,7 +7,7 @@ import java.util.HashMap; import java.util.Map; -public record BlockEntry(NamespacedId id, Map propertyPredicates) { +public record BlockEntry(NamespacedId id, Map propertyPredicates) implements Entry { /** * Parses a block ID entry. @@ -15,11 +15,55 @@ public record BlockEntry(NamespacedId id, Map propertyPredicates * @param entry The string representation of the entry. Must not be empty. */ @NotNull - public static BlockEntry parse(@NotNull String entry) { + public static Entry parse(@NotNull String entry) { if (entry.isEmpty()) { throw new IllegalArgumentException("Called BlockEntry::parse with an empty string"); } + if (entry.startsWith("%")) { + entry = entry.replace("%", ""); + // It's a tag! + String[] splitStates = entry.split(":"); + + if (splitStates.length == 1) { + return new TagEntry(new NamespacedId("minecraft", entry), Map.of()); + } else if (splitStates.length == 2 && !splitStates[1].contains("=")) { + return new TagEntry(new NamespacedId(splitStates[0], splitStates[1]), Map.of()); + } else { + // Complex case: One or more states involved... + int statesStart; + NamespacedId id; + + if (splitStates[1].contains("=")) { + // We have an entry of the form "tall_grass:half=upper" + statesStart = 1; + id = new NamespacedId("minecraft", splitStates[0]); + } else { + // We have an entry of the form "minecraft:tall_grass:half=upper" + statesStart = 2; + id = new NamespacedId(splitStates[0], splitStates[1]); + } + + Map map = new HashMap<>(); + + for (int index = statesStart; index < splitStates.length; index++) { + String[] propertyParts = splitStates[index].split("="); + + if (propertyParts.length != 2) { + Iris.logger.warn("Warning: the block ID map entry \"" + entry + "\" could not be fully parsed:"); + Iris.logger.warn("- Block state property filters must be of the form \"key=value\", but " + + splitStates[index] + " is not of that form!"); + + continue; + } + + map.put(propertyParts[0], propertyParts[1]); + } + + return new TagEntry(id, map); + } + } + // We can assume that this array is of at least array length because the input string is non-empty. String[] splitStates = entry.split(":"); diff --git a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockMaterialMapping.java b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockMaterialMapping.java index 47b8b6c802..9fc7061e05 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockMaterialMapping.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/BlockMaterialMapping.java @@ -1,13 +1,17 @@ package net.irisshaders.iris.shaderpack.materialmap; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import net.irisshaders.iris.Iris; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; @@ -15,12 +19,13 @@ import net.minecraft.world.level.block.state.properties.Property; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class BlockMaterialMapping { - public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { - Object2IntMap blockStateIds = new Object2IntOpenHashMap<>(); + public static Object2IntMap createBlockStateIdMap(Int2ObjectLinkedOpenHashMap> blockPropertiesMap, Int2ObjectLinkedOpenHashMap> tagPropertiesMap) { + Object2IntMap blockStateIds = new Object2IntLinkedOpenHashMap<>(); blockPropertiesMap.forEach((intId, entries) -> { for (BlockEntry entry : entries) { @@ -28,11 +33,75 @@ public static Object2IntMap createBlockStateIdMap(Int2ObjectMap { + for (TagEntry entry : entries) { + addTag(entry, blockStateIds, intId); + } + }); + return blockStateIds; } + private static void addTag(TagEntry tagEntry, Object2IntMap idMap, int intId) { + List> compatibleTags = BuiltInRegistries.BLOCK.getTagNames().filter(t -> t.location().getNamespace().equalsIgnoreCase(tagEntry.id().getNamespace()) && + t.location().getPath().equalsIgnoreCase(tagEntry.id().getName())).toList(); + + if (compatibleTags.isEmpty()) { + Iris.logger.warn("Failed to find the tag " + tagEntry.id()); + } else if (compatibleTags.size() > 1) { + Iris.logger.fatal("You've broke the system; congrats. More than one tag matched " + tagEntry.id()); + } else { + BuiltInRegistries.BLOCK.getTag(compatibleTags.get(0)).get().forEach((block) -> { + Map propertyPredicates = tagEntry.propertyPredicates(); + + if (propertyPredicates.isEmpty()) { + // Just add all the states if there aren't any predicates + for (BlockState state : block.value().getStateDefinition().getPossibleStates()) { + // NB: Using putIfAbsent means that the first successful mapping takes precedence + // Needed for OptiFine parity: + // https://github.com/IrisShaders/Iris/issues/1327 + idMap.putIfAbsent(state, intId); + } + + return; + } + + // As a result, we first collect each key=value pair in order to determine what properties we need to filter on. + // We already get this from BlockEntry, but we convert the keys to `Property`s to ensure they exist and to avoid + // string comparisons later. + Map, String> properties = new LinkedHashMap<>(); + StateDefinition stateManager = block.value().getStateDefinition(); + + propertyPredicates.forEach((key, value) -> { + Property property = stateManager.getProperty(key); + + if (property == null) { + Iris.logger.warn("Error while parsing the block ID map entry for tag \"" + "block." + intId + "\":"); + Iris.logger.warn("- The block " + block.unwrapKey().get().location() + " has no property with the name " + key + ", ignoring!"); + + return; + } + + properties.put(property, value); + }); + + // Once we have a list of properties and their expected values, we iterate over every possible state of this + // block and check for ones that match the filters. This isn't particularly efficient, but it works! + for (BlockState state : stateManager.getPossibleStates()) { + if (checkState(state, properties)) { + // NB: Using putIfAbsent means that the first successful mapping takes precedence + // Needed for OptiFine parity: + // https://github.com/IrisShaders/Iris/issues/1327 + idMap.putIfAbsent(state, intId); + } + } + } + ); + } + } + public static Map createBlockTypeMap(Map blockPropertiesMap) { - Map blockTypeIds = new Reference2ReferenceOpenHashMap<>(); + Map blockTypeIds = new Reference2ReferenceLinkedOpenHashMap<>(); blockPropertiesMap.forEach((id, blockType) -> { ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); @@ -92,7 +161,7 @@ private static void addBlockStates(BlockEntry entry, Object2IntMap i // As a result, we first collect each key=value pair in order to determine what properties we need to filter on. // We already get this from BlockEntry, but we convert the keys to `Property`s to ensure they exist and to avoid // string comparisons later. - Map, String> properties = new HashMap<>(); + Map, String> properties = new LinkedHashMap<>(); StateDefinition stateManager = block.getStateDefinition(); propertyPredicates.forEach((key, value) -> { diff --git a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/Entry.java b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/Entry.java new file mode 100644 index 0000000000..adf0dfb6be --- /dev/null +++ b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/Entry.java @@ -0,0 +1,4 @@ +package net.irisshaders.iris.shaderpack.materialmap; + +public interface Entry { +} diff --git a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/LegacyIdMap.java b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/LegacyIdMap.java index bddc1bca11..b91b7116fb 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/LegacyIdMap.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/LegacyIdMap.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import it.unimi.dsi.fastutil.Function; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import java.util.ArrayList; @@ -17,7 +18,7 @@ public class LegacyIdMap { private static final ImmutableList WOOD_TYPES = ImmutableList.of("oak", "birch", "jungle", "spruce", "acacia", "dark_oak"); - public static void addLegacyValues(Int2ObjectMap> blockIdMap) { + public static void addLegacyValues(Int2ObjectLinkedOpenHashMap> blockIdMap) { add(blockIdMap, 1, block("stone"), block("granite"), block("diorite"), block("andesite")); add(blockIdMap, 2, block("grass_block")); add(blockIdMap, 4, block("cobblestone")); @@ -80,7 +81,7 @@ private static BlockEntry block(String name) { return new BlockEntry(new NamespacedId("minecraft", name), Collections.emptyMap()); } - private static void addMany(Int2ObjectMap> blockIdMap, int id, List prefixes, Function toId) { + private static void addMany(Int2ObjectLinkedOpenHashMap> blockIdMap, int id, List prefixes, Function toId) { List entries = new ArrayList<>(); for (String prefix : prefixes) { diff --git a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/NamespacedId.java b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/NamespacedId.java index 2c47e6b234..27d3366a74 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/NamespacedId.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/NamespacedId.java @@ -57,9 +57,6 @@ public int hashCode() { @Override public String toString() { - return "NamespacedId{" + - "namespace='" + namespace + '\'' + - ", name='" + name + '\'' + - '}'; + return namespace + ":" + name; } } diff --git a/src/main/java/net/irisshaders/iris/shaderpack/materialmap/TagEntry.java b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/TagEntry.java new file mode 100644 index 0000000000..1cc6dd0860 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/shaderpack/materialmap/TagEntry.java @@ -0,0 +1,6 @@ +package net.irisshaders.iris.shaderpack.materialmap; + +import java.util.Map; + +public record TagEntry(NamespacedId id, Map propertyPredicates) implements Entry { +} diff --git a/src/main/java/net/irisshaders/iris/shaderpack/option/values/OptionValues.java b/src/main/java/net/irisshaders/iris/shaderpack/option/values/OptionValues.java index db74ed7af4..20f120f4f0 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/option/values/OptionValues.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/option/values/OptionValues.java @@ -12,6 +12,12 @@ public interface OptionValues { Optional getStringValue(String name); default boolean getBooleanValueOrDefault(String name) { + if ("0".equals(name)) { + return false; + } else if ("1".equals(name)) { + return true; + } + return getBooleanValue(name).orElseGet(() -> { if (!getOptionSet().getBooleanOptions().containsKey(name)) { Iris.logger.warn("Tried to get boolean value for unknown option: " + name + ", defaulting to true!"); diff --git a/src/main/java/net/irisshaders/iris/shaderpack/parsing/BooleanParser.java b/src/main/java/net/irisshaders/iris/shaderpack/parsing/BooleanParser.java new file mode 100644 index 0000000000..61d53003d8 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/shaderpack/parsing/BooleanParser.java @@ -0,0 +1,150 @@ +package net.irisshaders.iris.shaderpack.parsing; + +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.shaderpack.option.values.OptionValues; + +import java.util.EmptyStackException; +import java.util.Stack; + +public class BooleanParser { + private enum Operation { + AND { + @Override + boolean compute(boolean value, Stack valueStack) { + return valueStack.pop() && value; + } + }, OR { + @Override + boolean compute(boolean value, Stack valueStack) { + return valueStack.pop() || value; + } + }, NOT { + @Override + boolean compute(boolean value, Stack valueStack) { + return !value; + } + }, OPEN; + + boolean compute(boolean value, Stack valueStack) { + return value; + } + } + + /** + * parses the given expression + * @param expression expression to parse + * @param valueLookup lookup of shadow options + * @return result of the expression, or true if there was an error + */ + public static boolean parse(String expression, OptionValues valueLookup) { + try { + String option = ""; + Stack operationStack = new Stack<>(); + Stack valueStack = new Stack<>(); + for (int i = 0; i < expression.length(); i++) { + char c = expression.charAt(i); + switch (c) { + case '!' -> operationStack.push(Operation.NOT); + case '&' -> { + // add value first, because this checks for preceding NOTs + if (!option.isEmpty()) { + valueStack.push(processValue(option, valueLookup, operationStack)); + option = ""; + } + // AND operators have priority, so add a bracket if it's the first AND + if (operationStack.isEmpty() || !operationStack.peek().equals(Operation.AND)) { + operationStack.push(Operation.OPEN); + } + i++; + operationStack.push(Operation.AND); + } + case '|' -> { + // add value first, because this checks for preceding NOTs + if (!option.isEmpty()) { + valueStack.push(processValue(option, valueLookup, operationStack)); + option = ""; + } + // if there was an AND before, that needs to be evaluated because it takes priority + if (!operationStack.isEmpty() && operationStack.peek().equals(Operation.AND)) { + evaluate(operationStack, valueStack, true); + } + i++; + operationStack.push(Operation.OR); + } + case '(' -> operationStack.push(Operation.OPEN); + case ')' -> { + // add value first, because this checks for preceding NOTs + if (!option.isEmpty()) { + valueStack.push(processValue(option, valueLookup, operationStack)); + option = ""; + } + // if there was an AND before, that needs to be evaluated because it added its own bracket + if (!operationStack.isEmpty() && operationStack.peek().equals(Operation.AND)) { + evaluate(operationStack, valueStack, true); + } + evaluate(operationStack, valueStack, true); + } + case ' ' -> {} + default -> option += c; + } + } + if (!option.isEmpty()) { + valueStack.push(processValue(option, valueLookup, operationStack)); + } + evaluate(operationStack, valueStack, false); + boolean result = valueStack.pop(); + if (!valueStack.isEmpty() || !operationStack.isEmpty()) { + Iris.logger.warn( + "Failed to parse the following boolean operation correctly, stacks not empty, defaulting to true!: '{}'", + expression); + return true; + } + return result; + } catch (EmptyStackException emptyStackException) { + Iris.logger.warn( + "Failed to parse the following boolean operation correctly, stacks empty when it shouldn't, defaulting to true!: '{}'", + expression); + return true; + } + } + + /** + * gets the value for the given string and negates it if there is a NOT in the operationStack + */ + private static boolean processValue(String value, OptionValues valueLookup, Stack operationStack) { + boolean booleanValue = switch (value) { + case "true", "1" -> true; + case "false", "0" -> false; + default -> valueLookup != null && valueLookup.getBooleanValueOrDefault(value); + }; + if (!operationStack.isEmpty() && operationStack.peek() == Operation.NOT) { + // if there is a NOT, that needs to be handled immediately + operationStack.pop(); + return !booleanValue; + } else { + return booleanValue; + } + } + + /** + * evaluates the operation stack backwards, to the next bracket, or the whole way + * @param operationStack Stack with operations + * @param valueStack Stack with values + * @param currentBracket only evaluates the current bracket + */ + private static void evaluate(Stack operationStack, Stack valueStack, boolean currentBracket) { + boolean value = valueStack.pop(); + while (!operationStack.isEmpty() && (!currentBracket || operationStack.peek() != Operation.OPEN)) { + value = operationStack.pop().compute(value, valueStack); + } + + // if there is a bracket check if the whole bracket should be negated + if (!operationStack.isEmpty() && operationStack.peek() == Operation.OPEN) { + operationStack.pop(); + if (!operationStack.isEmpty() && operationStack.peek() == Operation.NOT) { + value = operationStack.pop().compute(value, valueStack); + } + } + valueStack.push(value); + } +} diff --git a/src/main/java/net/irisshaders/iris/shaderpack/parsing/ParsedString.java b/src/main/java/net/irisshaders/iris/shaderpack/parsing/ParsedString.java index dfad869035..7014d57de6 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/parsing/ParsedString.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/parsing/ParsedString.java @@ -104,11 +104,18 @@ public String takeNumber() { if (!Character.isDigit(text.charAt(position)) && !Character.isDigit(text.charAt(position + 1))) { break; } + } else if (!Character.isDigit(text.charAt(position))) { + break; } position++; } + // take any f float suffixes, if we have a number + if (position > 0 && position + 1 < text.length() && (text.charAt(position) == 'f' || text.charAt(position) == 'F')) { + position++; + } + try { Float.parseFloat(text.substring(0, position)); } catch (Exception e) { diff --git a/src/main/java/net/irisshaders/iris/shaderpack/preprocessor/PropertiesPreprocessor.java b/src/main/java/net/irisshaders/iris/shaderpack/preprocessor/PropertiesPreprocessor.java index 30b6c721e9..79f0f3f0b3 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/preprocessor/PropertiesPreprocessor.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/preprocessor/PropertiesPreprocessor.java @@ -17,9 +17,13 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class PropertiesPreprocessor { + + public static final Pattern BACKSLASH_MATCHER = Pattern.compile("(? environmentDefines) { if (source.contains(PropertyCollectingListener.PROPERTY_MARKER) || source.contains("IRIS_PASSTHROUGHBACKSLASH")) { @@ -35,7 +39,11 @@ public static String preprocessSource(String source, ShaderPackOptions shaderPac } for (StringPair envDefine : environmentDefines) { - pp.addMacro(envDefine.key(), envDefine.value()); + if (envDefine.value().isEmpty()) { + pp.addMacro(envDefine.key()); + } else { + pp.addMacro(envDefine.key(), envDefine.value()); + } } stringValues.forEach((name, value) -> { diff --git a/src/main/java/net/irisshaders/iris/shaderpack/programs/ProgramSet.java b/src/main/java/net/irisshaders/iris/shaderpack/programs/ProgramSet.java index d7bedc0027..3b705822a8 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/programs/ProgramSet.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/programs/ProgramSet.java @@ -5,6 +5,7 @@ import net.irisshaders.iris.gl.blending.BlendModeOverride; import net.irisshaders.iris.shaderpack.ShaderPack; import net.irisshaders.iris.shaderpack.include.AbsolutePackPath; +import net.irisshaders.iris.shaderpack.loading.ProgramArrayId; import net.irisshaders.iris.shaderpack.loading.ProgramId; import net.irisshaders.iris.shaderpack.parsing.ComputeDirectiveParser; import net.irisshaders.iris.shaderpack.parsing.ConstDirectiveParser; @@ -16,6 +17,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumMap; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -23,52 +25,16 @@ public class ProgramSet implements ProgramSetInterface { private final PackDirectives packDirectives; - private final ProgramSource shadow; private final ComputeSource[] shadowCompute; + private final ComputeSource[] finalCompute; - private final ProgramSource[] shadowcomp; - private final ComputeSource[][] shadowCompCompute; - private final ProgramSource[] begin; - private final ComputeSource[][] beginCompute; - private final ProgramSource[] prepare; - private final ComputeSource[][] prepareCompute; private final ComputeSource[] setup; - private final ProgramSource gbuffersBasic; - private final ProgramSource gbuffersLine; - private final ProgramSource gbuffersBeaconBeam; - private final ProgramSource gbuffersTextured; - private final ProgramSource gbuffersTexturedLit; - private final ProgramSource gbuffersTerrain; - private final ProgramSource gbuffersTerrainSolid; - private final ProgramSource gbuffersTerrainCutout; - private final ProgramSource gbuffersSkyBasic; - private final ProgramSource gbuffersSkyTextured; - private final ProgramSource gbuffersClouds; - private final ProgramSource gbuffersWeather; - private final ProgramSource gbuffersEntities; - private final ProgramSource gbuffersEntitiesTrans; - private final ProgramSource gbuffersParticles; - private final ProgramSource gbuffersParticlesTrans; - private final ProgramSource gbuffersEntitiesGlowing; - private final ProgramSource gbuffersGlint; - private final ProgramSource gbuffersEntityEyes; - private final ProgramSource gbuffersBlock; - private final ProgramSource gbuffersBlockTrans; - private final ProgramSource gbuffersHand; - private final ProgramSource[] deferred; - private final ComputeSource[][] deferredCompute; - private final ProgramSource gbuffersWater; - private final ProgramSource gbuffersHandWater; - private final ProgramSource[] composite; - private final ComputeSource[][] compositeCompute; - private final ProgramSource compositeFinal; - private final ComputeSource[] finalCompute; - private final ProgramSource dhTerrain; - private final ProgramSource dhWater; - private final ProgramSource dhShadow; private final ShaderPack pack; - private final ProgramSource gbuffersDamagedBlock; + + private final EnumMap gbufferPrograms = new EnumMap<>(ProgramId.class); + private final EnumMap compositePrograms = new EnumMap<>(ProgramArrayId.class); + private final EnumMap computePrograms = new EnumMap<>(ProgramArrayId.class); public ProgramSet(AbsolutePackPath directory, Function sourceProvider, ShaderProperties shaderProperties, ShaderPack pack) { @@ -85,91 +51,30 @@ public ProgramSet(AbsolutePackPath directory, Function // // - https://github.com/IrisShaders/Iris/issues/483 // - https://github.com/IrisShaders/Iris/issues/987 - boolean readTesselation = pack.hasFeature(FeatureFlags.TESSELATION_SHADERS); + boolean readTesselation = pack.hasFeature(FeatureFlags.TESSELLATION_SHADERS); - this.shadow = readProgramSource(directory, sourceProvider, "shadow", this, shaderProperties, - BlendModeOverride.OFF, readTesselation); this.shadowCompute = readComputeArray(directory, sourceProvider, "shadow", shaderProperties); - - this.shadowcomp = readProgramArray(directory, sourceProvider, "shadowcomp", shaderProperties, readTesselation); - - this.shadowCompCompute = new ComputeSource[shadowcomp.length][]; - for (int i = 0; i < shadowcomp.length; i++) { - this.shadowCompCompute[i] = readComputeArray(directory, sourceProvider, "shadowcomp" + ((i == 0) ? "" : i), shaderProperties); - } - this.setup = readProgramArray(directory, sourceProvider, "setup", shaderProperties); - this.begin = readProgramArray(directory, sourceProvider, "begin", shaderProperties, readTesselation); - this.beginCompute = new ComputeSource[begin.length][]; - for (int i = 0; i < begin.length; i++) { - this.beginCompute[i] = readComputeArray(directory, sourceProvider, "begin" + ((i == 0) ? "" : i), shaderProperties); - } - - this.prepare = readProgramArray(directory, sourceProvider, "prepare", shaderProperties, readTesselation); - this.prepareCompute = new ComputeSource[prepare.length][]; - for (int i = 0; i < prepare.length; i++) { - this.prepareCompute[i] = readComputeArray(directory, sourceProvider, "prepare" + ((i == 0) ? "" : i), shaderProperties); + for (ProgramArrayId id : ProgramArrayId.values()) { + ProgramSource[] sources = readProgramArray(directory, sourceProvider, id.getSourcePrefix(), shaderProperties, readTesselation); + compositePrograms.put(id, sources); + ComputeSource[][] computes = new ComputeSource[id.getNumPrograms()][]; + for (int i = 0; i < id.getNumPrograms(); i++) { + computes[i] = readComputeArray(directory, sourceProvider, id.getSourcePrefix() + (i == 0 ? "" : i), shaderProperties); + } + computePrograms.put(id, computes); } - this.gbuffersBasic = readProgramSource(directory, sourceProvider, "gbuffers_basic", this, shaderProperties, readTesselation); - this.gbuffersLine = readProgramSource(directory, sourceProvider, "gbuffers_line", this, shaderProperties, readTesselation); - this.gbuffersBeaconBeam = readProgramSource(directory, sourceProvider, "gbuffers_beaconbeam", this, shaderProperties, readTesselation); - this.gbuffersTextured = readProgramSource(directory, sourceProvider, "gbuffers_textured", this, shaderProperties, readTesselation); - this.gbuffersTexturedLit = readProgramSource(directory, sourceProvider, "gbuffers_textured_lit", this, shaderProperties, readTesselation); - this.gbuffersTerrain = readProgramSource(directory, sourceProvider, "gbuffers_terrain", this, shaderProperties, readTesselation); - this.gbuffersTerrainSolid = readProgramSource(directory, sourceProvider, "gbuffers_terrain_solid", this, shaderProperties, readTesselation); - this.gbuffersTerrainCutout = readProgramSource(directory, sourceProvider, "gbuffers_terrain_cutout", this, shaderProperties, readTesselation); - this.gbuffersDamagedBlock = readProgramSource(directory, sourceProvider, "gbuffers_damagedblock", this, shaderProperties, readTesselation); - this.gbuffersSkyBasic = readProgramSource(directory, sourceProvider, "gbuffers_skybasic", this, shaderProperties, readTesselation); - this.gbuffersSkyTextured = readProgramSource(directory, sourceProvider, "gbuffers_skytextured", this, shaderProperties, readTesselation); - this.gbuffersClouds = readProgramSource(directory, sourceProvider, "gbuffers_clouds", this, shaderProperties, readTesselation); - this.gbuffersWeather = readProgramSource(directory, sourceProvider, "gbuffers_weather", this, shaderProperties, readTesselation); - this.gbuffersEntities = readProgramSource(directory, sourceProvider, "gbuffers_entities", this, shaderProperties, readTesselation); - this.gbuffersEntitiesTrans = readProgramSource(directory, sourceProvider, "gbuffers_entities_translucent", this, shaderProperties, readTesselation); - this.gbuffersParticles = readProgramSource(directory, sourceProvider, "gbuffers_particles", this, shaderProperties, readTesselation); - this.gbuffersParticlesTrans = readProgramSource(directory, sourceProvider, "gbuffers_particles_translucent", this, shaderProperties, readTesselation); - this.gbuffersEntitiesGlowing = readProgramSource(directory, sourceProvider, "gbuffers_entities_glowing", this, shaderProperties, readTesselation); - this.gbuffersGlint = readProgramSource(directory, sourceProvider, "gbuffers_armor_glint", this, shaderProperties, readTesselation); - this.gbuffersEntityEyes = readProgramSource(directory, sourceProvider, "gbuffers_spidereyes", this, shaderProperties, readTesselation); - this.gbuffersBlock = readProgramSource(directory, sourceProvider, "gbuffers_block", this, shaderProperties, readTesselation); - this.gbuffersBlockTrans = readProgramSource(directory, sourceProvider, "gbuffers_block_translucent", this, shaderProperties, readTesselation); - this.gbuffersHand = readProgramSource(directory, sourceProvider, "gbuffers_hand", this, shaderProperties, readTesselation); - this.dhTerrain = readProgramSource(directory, sourceProvider, "dh_terrain", this, shaderProperties, readTesselation); - this.dhWater = readProgramSource(directory, sourceProvider, "dh_water", this, shaderProperties, readTesselation); - this.dhShadow = readProgramSource(directory, sourceProvider, "dh_shadow", this, shaderProperties, readTesselation); - - this.deferred = readProgramArray(directory, sourceProvider, "deferred", shaderProperties, readTesselation); - this.deferredCompute = new ComputeSource[deferred.length][]; - for (int i = 0; i < deferred.length; i++) { - this.deferredCompute[i] = readComputeArray(directory, sourceProvider, "deferred" + ((i == 0) ? "" : i), shaderProperties); + for (ProgramId programId : ProgramId.values()) { + gbufferPrograms.put(programId, readProgramSource(directory, sourceProvider, programId.getSourceName(), this, shaderProperties, programId.getBlendModeOverride(), readTesselation)); } - this.gbuffersWater = readProgramSource(directory, sourceProvider, "gbuffers_water", this, shaderProperties, readTesselation); - this.gbuffersHandWater = readProgramSource(directory, sourceProvider, "gbuffers_hand_water", this, shaderProperties, readTesselation); - - this.composite = readProgramArray(directory, sourceProvider, "composite", shaderProperties, readTesselation); - this.compositeCompute = new ComputeSource[composite.length][]; - for (int i = 0; i < deferred.length; i++) { - this.compositeCompute[i] = readComputeArray(directory, sourceProvider, "composite" + ((i == 0) ? "" : i), shaderProperties); - } - this.compositeFinal = readProgramSource(directory, sourceProvider, "final", this, shaderProperties, readTesselation); this.finalCompute = readComputeArray(directory, sourceProvider, "final", shaderProperties); locateDirectives(); } - @SafeVarargs - private static Optional first(Optional... candidates) { - for (Optional candidate : candidates) { - if (candidate.isPresent()) { - return candidate; - } - } - - return Optional.empty(); - } - private static ProgramSource readProgramSource(AbsolutePackPath directory, Function sourceProvider, String program, ProgramSet programSet, ShaderProperties properties, boolean readTesselation) { @@ -286,17 +191,17 @@ private void locateDirectives() { List programs = new ArrayList<>(); List computes = new ArrayList<>(); - programs.add(shadow); - programs.addAll(Arrays.asList(shadowcomp)); - programs.addAll(Arrays.asList(begin)); - programs.addAll(Arrays.asList(prepare)); + programs.addAll(Arrays.asList(getComposite(ProgramArrayId.ShadowComposite))); + programs.addAll(Arrays.asList(getComposite(ProgramArrayId.Begin))); + programs.addAll(Arrays.asList(getComposite(ProgramArrayId.Prepare))); - programs.addAll(Arrays.asList( - gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain, gbuffersTerrainSolid, gbuffersTerrainCutout, - gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather, - gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans, - gbuffersHand, dhShadow, dhTerrain, dhWater - )); + for (ComputeSource[][] sources : computePrograms.values()) { + for (ComputeSource[] source : sources) { + computes.addAll(Arrays.asList(source)); + } + } + + programs.addAll(gbufferPrograms.values()); for (ComputeSource computeSource : setup) { if (computeSource != null) { @@ -304,25 +209,8 @@ private void locateDirectives() { } } - for (ComputeSource[] computeSources : beginCompute) { - computes.addAll(Arrays.asList(computeSources)); - } - - for (ComputeSource[] computeSources : compositeCompute) { - computes.addAll(Arrays.asList(computeSources)); - } - - for (ComputeSource[] computeSources : deferredCompute) { - computes.addAll(Arrays.asList(computeSources)); - } - - for (ComputeSource[] computeSources : prepareCompute) { - computes.addAll(Arrays.asList(computeSources)); - } - - for (ComputeSource[] computeSources : shadowCompCompute) { - computes.addAll(Arrays.asList(computeSources)); - } + programs.addAll(Arrays.asList(getComposite(ProgramArrayId.Deferred))); + programs.addAll(Arrays.asList(getComposite(ProgramArrayId.Composite))); Collections.addAll(computes, finalCompute); Collections.addAll(computes, shadowCompute); @@ -341,12 +229,6 @@ private void locateDirectives() { } } - programs.addAll(Arrays.asList(deferred)); - programs.add(gbuffersWater); - programs.add(gbuffersHandWater); - programs.addAll(Arrays.asList(composite)); - programs.add(compositeFinal); - DispatchingDirectiveHolder packDirectiveHolder = new DispatchingDirectiveHolder(); packDirectives.acceptDirectivesFrom(packDirectiveHolder); @@ -367,206 +249,23 @@ private void locateDirectives() { Iris.logger.debug("Render target settings for colortex" + index + ": " + settings)); } - public Optional getShadow() { - return shadow.requireValid(); - } - - public ProgramSource[] getShadowComposite() { - return shadowcomp; - } - - public ProgramSource[] getBegin() { - return begin; - } - - public ProgramSource[] getPrepare() { - return prepare; - } - public ComputeSource[] getSetup() { return setup; } - public Optional getGbuffersBasic() { - return gbuffersBasic.requireValid(); - } - - public Optional getGbuffersBeaconBeam() { - return gbuffersBeaconBeam.requireValid(); - } - - public Optional getGbuffersTextured() { - return gbuffersTextured.requireValid(); - } - - public Optional getGbuffersTexturedLit() { - return gbuffersTexturedLit.requireValid(); - } - - public Optional getGbuffersTerrain() { - return gbuffersTerrain.requireValid(); - } - - public Optional getGbuffersTerrainSolid() { - return gbuffersTerrainSolid.requireValid(); - } - - public Optional getGbuffersTerrainCutout() { - return gbuffersTerrainCutout.requireValid(); - } - - public Optional getGbuffersDamagedBlock() { - return gbuffersDamagedBlock.requireValid(); - } - - public Optional getGbuffersSkyBasic() { - return gbuffersSkyBasic.requireValid(); - } - - public Optional getGbuffersSkyTextured() { - return gbuffersSkyTextured.requireValid(); - } - - public Optional getGbuffersClouds() { - return gbuffersClouds.requireValid(); - } - - public Optional getGbuffersWeather() { - return gbuffersWeather.requireValid(); - } - - public Optional getGbuffersEntities() { - return gbuffersEntities.requireValid(); - } - - public Optional getGbuffersEntitiesTrans() { - return gbuffersEntitiesTrans.requireValid(); - } - - public Optional getGbuffersParticles() { - return gbuffersParticles.requireValid(); - } - - public Optional getGbuffersParticlesTrans() { - return gbuffersParticlesTrans.requireValid(); - } - - public Optional getGbuffersEntitiesGlowing() { - return gbuffersEntitiesGlowing.requireValid(); - } - - public Optional getGbuffersGlint() { - return gbuffersGlint.requireValid(); - } - - public Optional getGbuffersEntityEyes() { - return gbuffersEntityEyes.requireValid(); - } - - public Optional getGbuffersBlock() { - return gbuffersBlock.requireValid(); - } - - public Optional getGbuffersBlockTrans() { - return gbuffersBlockTrans.requireValid(); - } - - public Optional getGbuffersHand() { - return gbuffersHand.requireValid(); - } - - public Optional getDhTerrain() { - return dhTerrain.requireValid(); - } - - public Optional getDhWater() { - return dhWater.requireValid(); - } - - public Optional getDhShadow() { - return dhShadow.requireValid(); - } - public Optional get(ProgramId programId) { - return switch (programId) { - case Shadow -> getShadow(); - case Basic -> getGbuffersBasic(); - case Line -> gbuffersLine.requireValid(); - case Textured -> getGbuffersTextured(); - case TexturedLit -> getGbuffersTexturedLit(); - case SkyBasic -> getGbuffersSkyBasic(); - case SkyTextured -> getGbuffersSkyTextured(); - case Clouds -> getGbuffersClouds(); - case Terrain -> getGbuffersTerrain(); - case TerrainSolid -> getGbuffersTerrainSolid(); - case TerrainCutout -> getGbuffersTerrainCutout(); - case DamagedBlock -> getGbuffersDamagedBlock(); - case Block -> getGbuffersBlock(); - case BlockTrans -> getGbuffersBlockTrans(); - case BeaconBeam -> getGbuffersBeaconBeam(); - case Entities -> getGbuffersEntities(); - case EntitiesTrans -> getGbuffersEntitiesTrans(); - case Particles -> getGbuffersParticles(); - case ParticlesTrans -> getGbuffersParticlesTrans(); - case EntitiesGlowing -> getGbuffersEntitiesGlowing(); - case ArmorGlint -> getGbuffersGlint(); - case SpiderEyes -> getGbuffersEntityEyes(); - case Hand -> getGbuffersHand(); - case Weather -> getGbuffersWeather(); - case Water -> getGbuffersWater(); - case HandWater -> getGbuffersHandWater(); - case Final -> getCompositeFinal(); - case DhTerrain -> getDhTerrain(); - case DhWater -> getDhWater(); - case DhShadow -> getDhShadow(); - default -> Optional.empty(); - }; - } - - public ProgramSource[] getDeferred() { - return deferred; - } - - public Optional getGbuffersWater() { - return gbuffersWater.requireValid(); - } - - public Optional getGbuffersHandWater() { - return gbuffersHandWater.requireValid(); - } - - public ProgramSource[] getComposite() { - return composite; - } - - public Optional getCompositeFinal() { - return compositeFinal.requireValid(); + ProgramSource source = gbufferPrograms.getOrDefault(programId, null); + if (source != null) { + return source.requireValid(); + } else { + return Optional.empty(); + } } public ComputeSource[] getShadowCompute() { return shadowCompute; } - public ComputeSource[][] getShadowCompCompute() { - return shadowCompCompute; - } - - public ComputeSource[][] getBeginCompute() { - return beginCompute; - } - - public ComputeSource[][] getPrepareCompute() { - return prepareCompute; - } - - public ComputeSource[][] getDeferredCompute() { - return deferredCompute; - } - - public ComputeSource[][] getCompositeCompute() { - return compositeCompute; - } - public ComputeSource[] getFinalCompute() { return finalCompute; } @@ -578,4 +277,12 @@ public PackDirectives getPackDirectives() { public ShaderPack getPack() { return pack; } + + public ProgramSource[] getComposite(ProgramArrayId programArrayId) { + return compositePrograms.getOrDefault(programArrayId, new ProgramSource[programArrayId.getNumPrograms()]); + } + + public ComputeSource[][] getCompute(ProgramArrayId programArrayId) { + return computePrograms.getOrDefault(programArrayId, new ComputeSource[programArrayId.getNumPrograms()][27]); + } } diff --git a/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java b/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java index d1b7e3a51b..14caef33ee 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java @@ -38,6 +38,7 @@ public class PackDirectives { private boolean separateAo; private boolean voxelizeLightBlocks; private boolean separateEntityDraws; + private boolean skipAllRendering; private boolean frustumCulling; private boolean occlusionCulling; private boolean oldLighting; @@ -75,6 +76,7 @@ public PackDirectives(Set supportedRenderTargets, ShaderProperties prop separateAo = properties.getSeparateAo().orElse(false); voxelizeLightBlocks = properties.getVoxelizeLightBlocks().orElse(false); separateEntityDraws = properties.getSeparateEntityDraws().orElse(false); + skipAllRendering = properties.skipAllRendering().orElse(false); frustumCulling = properties.getFrustumCulling().orElse(true); occlusionCulling = properties.getOcclusionCulling().orElse(true); oldLighting = properties.getOldLighting().orElse(false); @@ -202,6 +204,10 @@ public boolean isPrepareBeforeShadow() { return prepareBeforeShadow; } + public boolean skipAllRendering() { + return skipAllRendering; + } + public Object2ObjectMap, String> getTextureMap() { return textureMap; } diff --git a/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java b/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java index 1896e91294..6c45b722e6 100644 --- a/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java +++ b/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java @@ -100,6 +100,7 @@ public class ShaderProperties { private OptionalBoolean separateAo = OptionalBoolean.DEFAULT; private OptionalBoolean voxelizeLightBlocks = OptionalBoolean.DEFAULT; private OptionalBoolean separateEntityDraws = OptionalBoolean.DEFAULT; + private OptionalBoolean skipAllRendering = OptionalBoolean.DEFAULT; private OptionalBoolean frustumCulling = OptionalBoolean.DEFAULT; private OptionalBoolean occlusionCulling = OptionalBoolean.DEFAULT; private ShadowCullState shadowCulling = ShadowCullState.DEFAULT; @@ -199,6 +200,7 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It handleBooleanDirective(key, value, "frustum.culling", bool -> frustumCulling = bool); handleBooleanDirective(key, value, "occlusion.culling", bool -> occlusionCulling = bool); handleBooleanDirective(key, value, "shadow.enabled", bool -> shadowEnabled = bool); + handleBooleanDirective(key, value, "skipAllRendering", bool -> skipAllRendering = bool); handleBooleanDirective(key, value, "dhShadow.enabled", bool -> dhShadowEnabled = bool); handleBooleanDirective(key, value, "particles.before.deferred", bool -> { if (bool.orElse(false) && particleRenderingSettings.isEmpty()) { @@ -360,14 +362,14 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It handlePassDirective("bufferObject.", key, value, index -> { int trueIndex; - int trueSize; + long trueSize; boolean isRelative; float scaleX, scaleY; String[] parts = value.split(" "); if (parts.length == 1) { try { trueIndex = Integer.parseInt(index); - trueSize = Integer.parseInt(value); + trueSize = Long.parseLong(value); } catch (NumberFormatException e) { Iris.logger.error("Number format exception parsing SSBO index/size!", e); return; @@ -388,7 +390,7 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It // Assume it's a long one try { trueIndex = Integer.parseInt(index); - trueSize = Integer.parseInt(parts[0]); + trueSize = Long.parseLong(parts[0]); isRelative = Boolean.parseBoolean(parts[1]); scaleX = Float.parseFloat(parts[2]); scaleY = Float.parseFloat(parts[3]); @@ -597,9 +599,9 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It } private static void handleBooleanValue(String key, String value, BooleanConsumer handler) { - if ("true".equals(value)) { + if ("true".equals(value) || "1".equals(value)) { handler.accept(true); - } else if ("false".equals(value)) { + } else if ("false".equals(value) || "0".equals(value)) { handler.accept(false); } else { Iris.logger.warn("Unexpected value for boolean key " + key + " in shaders.properties: got " + value + ", but expected either true or false"); @@ -611,9 +613,9 @@ private static void handleBooleanDirective(String key, String value, String expe return; } - if ("true".equals(value)) { + if ("true".equals(value) || "1".equals(value)) { handler.accept(OptionalBoolean.TRUE); - } else if ("false".equals(value)) { + } else if ("false".equals(value) || "0".equals(value)) { handler.accept(OptionalBoolean.FALSE); } else { Iris.logger.warn("Unexpected value for boolean key " + key + " in shaders.properties: got " + value + ", but expected either true or false"); @@ -806,6 +808,10 @@ public OptionalBoolean getSeparateEntityDraws() { return separateEntityDraws; } + public OptionalBoolean skipAllRendering() { + return skipAllRendering; + } + public OptionalBoolean getFrustumCulling() { return frustumCulling; } diff --git a/src/main/java/net/irisshaders/iris/uniforms/BiomeUniforms.java b/src/main/java/net/irisshaders/iris/uniforms/BiomeUniforms.java index 0487391525..9aab46a646 100644 --- a/src/main/java/net/irisshaders/iris/uniforms/BiomeUniforms.java +++ b/src/main/java/net/irisshaders/iris/uniforms/BiomeUniforms.java @@ -5,7 +5,7 @@ import net.irisshaders.iris.gl.uniform.FloatSupplier; import net.irisshaders.iris.gl.uniform.UniformHolder; import net.irisshaders.iris.parsing.BiomeCategories; -import net.irisshaders.iris.parsing.ExtendedBiome; +import net.irisshaders.iris.mixinterface.ExtendedBiome; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Holder; diff --git a/src/main/java/net/irisshaders/iris/uniforms/CommonUniforms.java b/src/main/java/net/irisshaders/iris/uniforms/CommonUniforms.java index ac48c56151..e3a7967323 100644 --- a/src/main/java/net/irisshaders/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/irisshaders/iris/uniforms/CommonUniforms.java @@ -12,6 +12,7 @@ import net.irisshaders.iris.mixin.GlStateManagerAccessor; import net.irisshaders.iris.mixin.statelisteners.BooleanStateAccessor; import net.irisshaders.iris.mixin.texture.TextureAtlasAccessor; +import net.irisshaders.iris.mixinterface.LocalPlayerInterface; import net.irisshaders.iris.shaderpack.IdMap; import net.irisshaders.iris.shaderpack.properties.PackDirectives; import net.irisshaders.iris.texture.TextureInfoCache; @@ -155,6 +156,7 @@ public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNoti .uniform1i(ONCE, "currentRenderedItemId", () -> -1) .uniform1f(ONCE, "pi", () -> Math.PI) .uniform1f(PER_TICK, "playerMood", CommonUniforms::getPlayerMood) + .uniform1f(PER_TICK, "constantMood", CommonUniforms::getConstantMood) .uniform2i(PER_FRAME, "eyeBrightness", CommonUniforms::getEyeBrightness) .uniform2i(PER_FRAME, "eyeBrightnessSmooth", () -> { Vector2f smoothed = eyeBrightnessSmooth.get(); @@ -264,6 +266,15 @@ private static float getPlayerMood() { return Math.clamp(0.0F, 1.0F, ((LocalPlayer) client.cameraEntity).getCurrentMood()); } + private static float getConstantMood() { + if (!(client.cameraEntity instanceof LocalPlayer)) { + return 0.0F; + } + + // This should always be 0 to 1 anyways but just making sure + return Math.clamp(0.0F, 1.0F, ((LocalPlayerInterface) client.cameraEntity).getCurrentConstantMood()); + } + static float getRainStrength() { if (client.level == null) { return 0f; diff --git a/src/main/java/net/irisshaders/iris/uniforms/IrisExclusiveUniforms.java b/src/main/java/net/irisshaders/iris/uniforms/IrisExclusiveUniforms.java index ffa204339d..43f294b57f 100644 --- a/src/main/java/net/irisshaders/iris/uniforms/IrisExclusiveUniforms.java +++ b/src/main/java/net/irisshaders/iris/uniforms/IrisExclusiveUniforms.java @@ -4,19 +4,28 @@ import net.irisshaders.iris.gl.uniform.UniformUpdateFrequency; import net.irisshaders.iris.gui.option.IrisVideoSettings; import net.irisshaders.iris.helpers.JomlConversions; +import net.irisshaders.iris.mixin.GameRendererAccessor; +import net.irisshaders.iris.shaderpack.materialmap.WorldRenderingSettings; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; import net.minecraft.world.entity.LightningBolt; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import org.joml.Math; import org.joml.Vector3d; +import org.joml.Vector3f; import org.joml.Vector4f; import java.util.Objects; import java.util.stream.StreamSupport; +import static net.irisshaders.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; + public class IrisExclusiveUniforms { private static final Vector3d ZERO = new Vector3d(0); @@ -37,6 +46,8 @@ public static void addIrisExclusiveUniforms(UniformHolder uniforms) { uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "maxPlayerAir", IrisExclusiveUniforms::getMaxAir); uniforms.uniform1b(UniformUpdateFrequency.PER_FRAME, "firstPersonCamera", IrisExclusiveUniforms::isFirstPersonCamera); uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "isSpectator", IrisExclusiveUniforms::isSpectator); + uniforms.uniform1i(PER_FRAME, "currentSelectedBlockId", IrisExclusiveUniforms::getCurrentSelectedBlockId); + uniforms.uniform3f(PER_FRAME, "currentSelectedBlockPos", IrisExclusiveUniforms::getCurrentSelectedBlockPos); uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "eyePosition", IrisExclusiveUniforms::getEyePosition); uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "cloudTime", CapturedRenderingState.INSTANCE::getCloudTime); uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "relativeEyePosition", () -> CameraUniforms.getUnshiftedCameraPosition().sub(getEyePosition())); @@ -62,6 +73,29 @@ public static void addIrisExclusiveUniforms(UniformHolder uniforms) { }); } + private static int getCurrentSelectedBlockId() { + HitResult hitResult = Minecraft.getInstance().hitResult; + if (Minecraft.getInstance().level != null && ((GameRendererAccessor) Minecraft.getInstance().gameRenderer).shouldRenderBlockOutlineA() && hitResult != null && hitResult.getType() == HitResult.Type.BLOCK) { + BlockPos blockPos4 = ((BlockHitResult)hitResult).getBlockPos(); + BlockState blockState = Minecraft.getInstance().level.getBlockState(blockPos4); + if (!blockState.isAir() && Minecraft.getInstance().level.getWorldBorder().isWithinBounds(blockPos4)) { + return WorldRenderingSettings.INSTANCE.getBlockStateIds().getInt(blockState); + } + } + + return 0; + } + + private static Vector3f getCurrentSelectedBlockPos() { + HitResult hitResult = Minecraft.getInstance().hitResult; + if (Minecraft.getInstance().level != null && ((GameRendererAccessor) Minecraft.getInstance().gameRenderer).shouldRenderBlockOutlineA() && hitResult != null && hitResult.getType() == HitResult.Type.BLOCK) { + BlockPos blockPos4 = ((BlockHitResult)hitResult).getBlockPos(); + return blockPos4.getCenter().subtract(Minecraft.getInstance().gameRenderer.getMainCamera().getPosition()).toVector3f(); + } + + return new Vector3f(-256.0f); + } + private static float getThunderStrength() { // Note: Ensure this is in the range of 0 to 1 - some custom servers send out of range values. return Math.clamp(0.0F, 1.0F, diff --git a/src/main/java/net/irisshaders/iris/uniforms/custom/CustomUniforms.java b/src/main/java/net/irisshaders/iris/uniforms/custom/CustomUniforms.java index b7793869fd..93ad2fc4be 100644 --- a/src/main/java/net/irisshaders/iris/uniforms/custom/CustomUniforms.java +++ b/src/main/java/net/irisshaders/iris/uniforms/custom/CustomUniforms.java @@ -330,7 +330,6 @@ public void addVariable(String type, String name, String expression, boolean isU public CustomUniforms build( CustomUniformFixedInputUniformsHolder inputHolder ) { - Iris.logger.info("Starting custom uniform resolving"); return new CustomUniforms(inputHolder, this.variables); } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 5a90da6036..dcecfb15a9 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -41,7 +41,10 @@ "1.20.3", "1.20.4" ], - "sodium": "0.5.8" + "sodium": [ + "0.5.8", + "0.5.11" + ] }, "breaks": { "iris-explorer": "*", diff --git a/src/main/resources/mixins.iris.json b/src/main/resources/mixins.iris.json index 07214f013a..30c462cdac 100644 --- a/src/main/resources/mixins.iris.json +++ b/src/main/resources/mixins.iris.json @@ -10,6 +10,7 @@ "LevelRendererAccessor", "LightTextureAccessor", "MixinBiome", + "MixinBiomeAmbientSoundsHandler", "MixinBiomes", "MixinBlockStateBehavior", "MixinBooleanState", @@ -29,8 +30,10 @@ "MixinItemBlockRenderTypes", "MixinItemInHandRenderer", "MixinLevelRenderer", + "MixinLevelRenderer_SkipRendering", "MixinLightningBoltRenderer", "MixinLightTexture", + "MixinLocalPlayer", "MixinMinecraft_Images", "MixinMinecraft_Keybinds", "MixinMinecraft_PipelineManagement", @@ -40,6 +43,7 @@ "MixinProgram", "MixinProgramManager", "MixinProgramType", + "MixinQuickPlayDev", "MixinRenderSystem", "MixinRenderTarget", "MixinScreenEffectRenderer", @@ -54,7 +58,9 @@ "entity_render_context.MixinBlockEntityRenderDispatcher", "entity_render_context.MixinCapeLayer", "entity_render_context.MixinElytraLayer", + "entity_render_context.MixinEnderDragonRenderer", "entity_render_context.MixinEntityRenderDispatcher", + "entity_render_context.MixinEntityRenderer", "entity_render_context.MixinHorseArmorLayer", "entity_render_context.MixinHumanoidArmorLayer", "entity_render_context.MixinItemRenderer",