mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-26 14:24:30 +00:00
Majority shader fixes (#1868)
This commit is contained in:
1 parent
b27834cbd9
commit
76bf19c8f6
37 files changed
+707
-40
No files matched your search
@@ -16,6 +16,7 @@ import com.gtnewhorizons.angelica.glsm.hooks.DeferredDepthColorHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GlintColorHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CommandRecorder;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CompiledDisplayList;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.ImmediateModeRecorder;
|
||||
@@ -1613,6 +1614,11 @@ public class GLStateManager {
|
||||
ImmediateModeRecorder.setColor(red, green, blue, alpha);
|
||||
}
|
||||
dirtyColorAttrib = true;
|
||||
// Only set while an enchantment-glint span is active
|
||||
final GlintColorHandler glintHandler = GLSMHooks.glintColorHandler;
|
||||
if (glintHandler != null) {
|
||||
glintHandler.onColorChanged(red, green, blue, alpha);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -8,6 +8,7 @@ public final class GLSMHooks {
|
||||
public static DeferredBlendHandler blendHandler;
|
||||
public static DeferredAlphaHandler alphaHandler;
|
||||
public static DeferredDepthColorHandler depthColorHandler;
|
||||
public static GlintColorHandler glintColorHandler;
|
||||
|
||||
// EventBus instances
|
||||
public static final EventBus<TextureBindEvent> TEXTURE_BIND = EventBus.create(TextureBindEvent.class);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
|
||||
public interface GlintColorHandler {
|
||||
void onColorChanged(float red, float green, float blue, float alpha);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ public class ModStatus {
|
||||
public static boolean isCosmeticArmorReworkedLoaded;
|
||||
public static boolean isFluidLoggedLoaded;
|
||||
public static boolean isBOPLoaded;
|
||||
public static boolean isEtFuturumLoaded;
|
||||
|
||||
public static void preInit() {
|
||||
if (Loader.isModLoaded("backhand")) {
|
||||
@@ -49,6 +50,7 @@ public class ModStatus {
|
||||
isBaublesLoaded = Loader.isModLoaded("Baubles");
|
||||
isCosmeticArmorReworkedLoaded = Loader.isModLoaded("cosmeticarmorreworked");
|
||||
isFluidLoggedLoaded = Loader.isModLoaded("fluidlogged");
|
||||
isEtFuturumLoaded = Loader.isModLoaded("etfuturum");
|
||||
|
||||
isHoloInventoryLoaded = Loader.isModLoaded("holoinventory");
|
||||
isBOPLoaded = Loader.isModLoaded("BiomesOPlenty");
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.gtnewhorizons.angelica.compat.etfuturum;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.ModStatus.LOGGER;
|
||||
|
||||
public final class EtFuturumCompat {
|
||||
private static final String IELYTRA_PLAYER = "ganymedes01.etfuturum.api.elytra.IElytraPlayer";
|
||||
|
||||
@Getter
|
||||
private static boolean loaded;
|
||||
private static Class<?> elytraPlayerClass;
|
||||
private static final MethodHandle isElytraFlyingHandle;
|
||||
|
||||
static {
|
||||
MethodHandle handle = null;
|
||||
try {
|
||||
if (Loader.isModLoaded("etfuturum")) {
|
||||
elytraPlayerClass = ReflectionHelper.getClass(EtFuturumCompat.class.getClassLoader(), IELYTRA_PLAYER);
|
||||
handle = MethodHandles.lookup().findVirtual(elytraPlayerClass, "etfu$isElytraFlying",
|
||||
MethodType.methodType(boolean.class));
|
||||
loaded = true;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to load Et Futurum Requiem elytra compat", t);
|
||||
loaded = false;
|
||||
}
|
||||
isElytraFlyingHandle = handle;
|
||||
}
|
||||
|
||||
private EtFuturumCompat() {
|
||||
}
|
||||
|
||||
public static boolean isElytraFlying(EntityPlayer player) {
|
||||
if (!loaded || isElytraFlyingHandle == null || !elytraPlayerClass.isInstance(player)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return (boolean) isElytraFlyingHandle.invoke(player);
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,6 +298,7 @@ public enum Mixins implements IMixins {
|
||||
, "shaders.MixinRenderEndPortal"
|
||||
, "shaders.MixinTileEntityRendererDispatcher"
|
||||
, "shaders.MixinGlProgram"
|
||||
, "shaders.MixinTextureManager_ReloadCount"
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.gtnewhorizons.angelica.shadercompat;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GlintColorHandler;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
|
||||
import net.coderbot.iris.pipeline.ShadowRenderer;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Maybe overcomplicated, but it's required to bridge the gap between the modern glint texture and white texture 1.7.10
|
||||
* has. Some shaders are able to render the glint just fine as they seem to have some amount of support for older
|
||||
* Minecraft, but others like AstraLex do *not* render correctly. It expects the color to be within the texture.
|
||||
* This might introduce some oddities that I'm not seeing, but for now this appears to fix the issue.
|
||||
*/
|
||||
public final class ShaderGlint {
|
||||
|
||||
private static final ResourceLocation GLINT_MASK = new ResourceLocation("textures/misc/enchanted_item_glint.png");
|
||||
private static final int MAX_CACHE = 64;
|
||||
|
||||
private static boolean maskLoaded;
|
||||
private static boolean maskFailed;
|
||||
private static int maskW;
|
||||
private static int maskH;
|
||||
private static int[] maskLum;
|
||||
|
||||
private static final Int2IntLinkedOpenHashMap colorToTexture = new Int2IntLinkedOpenHashMap();
|
||||
static {
|
||||
colorToTexture.defaultReturnValue(0);
|
||||
}
|
||||
|
||||
private static final GlintColorHandler COLOR_HANDLER = ShaderGlint::onColorChanged;
|
||||
|
||||
private static boolean injecting;
|
||||
private static boolean swapped;
|
||||
private static int depth;
|
||||
|
||||
private static int prevTexture;
|
||||
|
||||
private static ByteBuffer tintBuffer;
|
||||
|
||||
private ShaderGlint() {}
|
||||
|
||||
public static void beginGlint() {
|
||||
if (ShadowRenderer.ACTIVE || !IrisApi.getInstance().isShaderPackInUse()) return;
|
||||
|
||||
// If a glint span is already active, keep the outer span's saved state and
|
||||
// let the nested render ride on its handler.
|
||||
if (depth++ > 0) return;
|
||||
|
||||
swapped = false;
|
||||
injecting = false;
|
||||
|
||||
// Save the texture bound before the glint section so endGlint can put it back if we swap
|
||||
prevTexture = GLStateManager.getBoundTextureForServerState(0);
|
||||
|
||||
// Observe vertex-color changes for the rest of the glint section
|
||||
GLSMHooks.glintColorHandler = COLOR_HANDLER;
|
||||
}
|
||||
|
||||
public static void endGlint() {
|
||||
if (depth == 0 || --depth > 0) return;
|
||||
if (GLSMHooks.glintColorHandler != COLOR_HANDLER) return;
|
||||
GLSMHooks.glintColorHandler = null;
|
||||
|
||||
if (swapped) {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, prevTexture);
|
||||
}
|
||||
swapped = false;
|
||||
injecting = false;
|
||||
}
|
||||
|
||||
private static void onColorChanged(float red, float green, float blue, float alpha) {
|
||||
if (injecting) return;
|
||||
|
||||
final int texture = getTintedTexture(red, green, blue);
|
||||
if (texture <= 0) return;
|
||||
|
||||
injecting = true;
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, alpha);
|
||||
injecting = false;
|
||||
swapped = true;
|
||||
}
|
||||
|
||||
private static int getTintedTexture(float r, float g, float b) {
|
||||
ensureMaskLoaded();
|
||||
if (!maskLoaded) return -1;
|
||||
|
||||
final int ri = clamp8(r);
|
||||
final int gi = clamp8(g);
|
||||
final int bi = clamp8(b);
|
||||
final int key = (ri << 16) | (gi << 8) | bi;
|
||||
|
||||
final int cached = colorToTexture.getAndMoveToLast(key);
|
||||
if (cached != 0) return cached;
|
||||
|
||||
if (colorToTexture.size() >= MAX_CACHE) {
|
||||
GLStateManager.glDeleteTextures(colorToTexture.remove(colorToTexture.firstIntKey()));
|
||||
}
|
||||
|
||||
final int texture = uploadTinted(ri / 255.0F, gi / 255.0F, bi / 255.0F);
|
||||
colorToTexture.putAndMoveToLast(key, texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private static int uploadTinted(float r, float g, float b) {
|
||||
final ByteBuffer pixels = tintBuffer;
|
||||
pixels.clear();
|
||||
for (final int l : maskLum) {
|
||||
pixels.put((byte) Math.round(l * r));
|
||||
pixels.put((byte) Math.round(l * g));
|
||||
pixels.put((byte) Math.round(l * b));
|
||||
pixels.put((byte) 0xFF);
|
||||
}
|
||||
pixels.flip();
|
||||
|
||||
final int texture = GLStateManager.glGenTextures();
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
// Match the vanilla glint texture
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, maskW, maskH, 0,
|
||||
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private static void ensureMaskLoaded() {
|
||||
if (maskLoaded || maskFailed) return;
|
||||
try (final InputStream in = Minecraft.getMinecraft().getResourceManager().getResource(GLINT_MASK).getInputStream()) {
|
||||
final BufferedImage img = ImageIO.read(in);
|
||||
maskW = img.getWidth();
|
||||
maskH = img.getHeight();
|
||||
maskLum = new int[maskW * maskH];
|
||||
final int[] argb = img.getRGB(0, 0, maskW, maskH, null, 0, maskW);
|
||||
for (int i = 0; i < argb.length; i++) {
|
||||
final int p = argb[i];
|
||||
final int rr = (p >> 16) & 0xFF;
|
||||
final int gg = (p >> 8) & 0xFF;
|
||||
final int bb = p & 0xFF;
|
||||
maskLum[i] = (rr + gg + bb) / 3;
|
||||
}
|
||||
tintBuffer = BufferUtils.createByteBuffer(maskW * maskH * 4);
|
||||
maskLoaded = true;
|
||||
} catch (final Exception e) {
|
||||
maskFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static int clamp8(float v) {
|
||||
final int i = Math.round(v * 255.0F);
|
||||
if (i < 0) return 0;
|
||||
return Math.min(i, 255);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import net.coderbot.iris.shaderpack.option.Profile;
|
||||
import net.coderbot.iris.shaderpack.option.values.MutableOptionValues;
|
||||
import net.coderbot.iris.shaderpack.option.values.OptionValues;
|
||||
import net.coderbot.iris.texture.pbr.PBRTextureManager;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
@@ -567,11 +568,11 @@ public class Iris {
|
||||
|
||||
// If it's a folder-based shaderpack, just use the shaders subdirectory
|
||||
shaderPackPath = shaderPackRoot.resolve("shaders");
|
||||
}
|
||||
|
||||
if (!Files.exists(shaderPackPath)) {
|
||||
logger.error("Could not load the shaderpack \"{}\" because it appears to lack a \"shaders\" directory", name);
|
||||
return false;
|
||||
if (!Files.exists(shaderPackPath)) {
|
||||
logger.error("Could not load the shaderpack \"{}\" because it appears to lack a \"shaders\" directory", name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -762,6 +763,9 @@ public class Iris {
|
||||
// allows shaderpacks to be changed at runtime
|
||||
irisConfig.initialize();
|
||||
|
||||
// Reset the texture reload counter
|
||||
CapturedRenderingState.INSTANCE.resetTextureReloadCount();
|
||||
|
||||
// Destroy all allocated resources
|
||||
destroyEverything();
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import java.util.function.BooleanSupplier;
|
||||
public enum FeatureFlags {
|
||||
SEPARATE_HARDWARE_SAMPLERS(() -> true, () -> true),
|
||||
PER_BUFFER_BLENDING(() -> true, RenderSystem::supportsBufferBlending),
|
||||
COMPUTE_SHADERS(() -> true, RenderSystem::supportsCompute),
|
||||
COMPUTE_SHADERS(() -> false, RenderSystem::supportsCompute),
|
||||
ENTITY_TRANSLUCENT(() -> true, () -> true),
|
||||
BLOCK_EMISSION_ATTRIBUTE(() -> true, () -> true),
|
||||
CUSTOM_IMAGES(() -> true, RenderSystem::supportsImageLoadStore),
|
||||
SSBO(() -> true, RenderSystem::supportsSSBO),
|
||||
HIGHER_SHADOWCOLOR(() -> true, () -> true),
|
||||
TESSELLATION_SHADERS(() -> true, RenderSystem::supportsTesselation),
|
||||
TESSELLATION_SHADERS(() -> false, RenderSystem::supportsTesselation),
|
||||
REVERSED_CULLING(() -> true, () -> true),
|
||||
CAN_DISABLE_WEATHER(() -> true, () -> true),
|
||||
UNKNOWN(() -> false, () -> false);
|
||||
|
||||
@@ -4,5 +4,7 @@ public enum GlVersion {
|
||||
GL_11,
|
||||
GL_12,
|
||||
GL_30,
|
||||
GL_31
|
||||
GL_31,
|
||||
GL_33,
|
||||
GL_41
|
||||
}
|
||||
@@ -132,6 +132,11 @@ public class StandardMacros {
|
||||
getBiomeCategoryDefines().forEach((category, ordinal) -> define(standardDefines, category, ordinal));
|
||||
getVanillaBiomeDefines().forEach((biome, id) -> define(standardDefines, biome, id));
|
||||
|
||||
// rain type constants
|
||||
define(standardDefines, "PPT_NONE", "0");
|
||||
define(standardDefines, "PPT_RAIN", "1");
|
||||
define(standardDefines, "PPT_SNOW", "2");
|
||||
|
||||
return ImmutableList.copyOf(standardDefines);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import net.coderbot.iris.gl.GlVersion;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
import org.lwjgl.opengl.GL41;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -72,10 +74,16 @@ public enum InternalTextureFormat {
|
||||
RG32UI(GL30.GL_RG32UI, GlVersion.GL_30, PixelFormat.RG_INTEGER),
|
||||
RGB32UI(GL30.GL_RGB32UI, GlVersion.GL_30, PixelFormat.RGB_INTEGER),
|
||||
RGBA32UI(GL30.GL_RGBA32UI, GlVersion.GL_30, PixelFormat.RGBA_INTEGER),
|
||||
// 2-bit normalized
|
||||
RGBA2(GL11.GL_RGBA2, GlVersion.GL_11, PixelFormat.RGBA),
|
||||
// 4-bit normalized
|
||||
RGBA4(GL11.GL_RGBA4, GlVersion.GL_11, PixelFormat.RGBA),
|
||||
// Mixed
|
||||
R3_G3_B2(GL11.GL_R3_G3_B2, GlVersion.GL_11, PixelFormat.RGB),
|
||||
RGB5_A1(GL11.GL_RGB5_A1, GlVersion.GL_11, PixelFormat.RGBA),
|
||||
RGB565(GL41.GL_RGB565, GlVersion.GL_41, PixelFormat.RGB),
|
||||
RGB10_A2(GL11.GL_RGB10_A2, GlVersion.GL_11, PixelFormat.RGBA),
|
||||
RGB10_A2UI(GL33.GL_RGB10_A2UI, GlVersion.GL_33, PixelFormat.RGBA_INTEGER),
|
||||
R11F_G11F_B10F(GL30.GL_R11F_G11F_B10F, GlVersion.GL_30, PixelFormat.RGB),
|
||||
RGB9_E5(GL30.GL_RGB9_E5, GlVersion.GL_30, PixelFormat.RGB);
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import net.coderbot.iris.gl.texture.DepthBufferFormat;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import net.coderbot.iris.helpers.Tri;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.transform.GlintScrollInjector;
|
||||
import net.coderbot.iris.pipeline.transform.PatchShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.TransformPatcher;
|
||||
import net.coderbot.iris.postprocess.BufferFlipper;
|
||||
@@ -838,13 +839,16 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
if (transformed == null) {
|
||||
// Fallback to synchronous transform if not pre-computed
|
||||
String vertex = source.getVertexSource().orElseThrow(NullPointerException::new);
|
||||
final boolean scrollGlint = GlintScrollInjector.shouldInject(id, source);
|
||||
transformed = TransformPatcher.patchAttributes(
|
||||
source.getVertexSource().orElseThrow(NullPointerException::new),
|
||||
vertex,
|
||||
source.getGeometrySource().orElse(null),
|
||||
source.getTessControlSource().orElse(null),
|
||||
source.getTessEvalSource().orElse(null),
|
||||
source.getFragmentSource().orElseThrow(NullPointerException::new),
|
||||
availability);
|
||||
availability,
|
||||
scrollGlint);
|
||||
}
|
||||
|
||||
String vertex = transformed.get(PatchShaderType.VERTEX);
|
||||
@@ -1784,9 +1788,12 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramSource source = resolver.resolveNullable(id);
|
||||
if (source != null && !processedSourceNames.contains(source.getName())) {
|
||||
processedSourceNames.add(source.getName());
|
||||
final ProgramSource src = source;
|
||||
final String vertexSource = src.getVertexSource().orElse(null);
|
||||
final boolean scrollGlint = GlintScrollInjector.shouldInject(id, src);
|
||||
for (InputAvailability avail : INPUT_AVAILABILITIES) {
|
||||
Pair<String, InputAvailability> key = Pair.of(source.getName(), avail);
|
||||
futures.put(key, Iris.ShaderTransformExecutor.submitTracked(() -> TransformPatcher.patchAttributes(source.getVertexSource().orElse(null), source.getGeometrySource().orElse(null), source.getTessControlSource().orElse(null), source.getTessEvalSource().orElse(null), source.getFragmentSource().orElse(null), avail)));
|
||||
Pair<String, InputAvailability> key = Pair.of(src.getName(), avail);
|
||||
futures.put(key, Iris.ShaderTransformExecutor.submitTracked(() -> TransformPatcher.patchAttributes(vertexSource, src.getGeometrySource().orElse(null), src.getTessControlSource().orElse(null), src.getTessEvalSource().orElse(null), src.getFragmentSource().orElse(null), avail, scrollGlint)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.coderbot.iris.pipeline.transform;
|
||||
import net.coderbot.iris.gl.shader.ShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.parameter.AttributeParameters;
|
||||
import org.taumc.glsl.Transformer;
|
||||
import org.taumc.glsl.grammar.GLSLParser;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -13,6 +14,10 @@ import java.util.Map;
|
||||
*/
|
||||
class AttributeTransformer {
|
||||
public static void transform(Transformer transformer, AttributeParameters parameters, int version) {
|
||||
if (parameters.scrollGlint && parameters.type == ShaderType.VERTEX) {
|
||||
transformer.replaceExpression("gl_MultiTexCoord0", "(gl_TextureMatrix[0] * gl_MultiTexCoord0)", GLSLParser::postfix_expression);
|
||||
}
|
||||
|
||||
// Always core profile — minimum GLSL version is 330 (see ShaderTransformer.getStageMinimumVersion)
|
||||
CommonTransformer.transform(transformer, parameters, true, version);
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ class CeleritasTransformer {
|
||||
vertexReplacements.put("gl_MultiTexCoord2", "iris_LightTexCoord");
|
||||
vertexReplacements.forEach(transformer::replaceExpression);
|
||||
|
||||
if (transformer.hasVariable("chunkOffset")) {
|
||||
transformer.removeVariable("chunkOffset");
|
||||
}
|
||||
|
||||
final Map<String, String> vertexRenames = new HashMap<>();
|
||||
vertexRenames.put("gl_Color", "_vert_color");
|
||||
vertexRenames.put("ftransform", "iris_ftransform");
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.glsm.GlslTransformUtils;
|
||||
import net.coderbot.iris.gl.shader.ShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
|
||||
import org.taumc.glsl.Transformer;
|
||||
import org.taumc.glsl.grammar.GLSLParser;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -29,6 +30,16 @@ public class CommonTransformer {
|
||||
root.rename("gl_Color", "iris_FrontColor");
|
||||
}
|
||||
|
||||
if (root.hasVariable("gl_TexCoord")) {
|
||||
if (parameters.type == ShaderType.VERTEX) {
|
||||
root.rename("gl_TexCoord", "irs_texCoords");
|
||||
root.injectVariable("out vec4 irs_texCoords[3];");
|
||||
} else if (parameters.type == ShaderType.FRAGMENT) {
|
||||
root.rename("gl_TexCoord", "irs_texCoords");
|
||||
root.injectVariable("in vec4 irs_texCoords[3];");
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.type == ShaderType.FRAGMENT) {
|
||||
if (root.containsCall("gl_FragColor")) {
|
||||
root.replaceExpression("gl_FragColor", "gl_FragData[0]");
|
||||
@@ -91,6 +102,27 @@ public class CommonTransformer {
|
||||
root.renameAndWrapShadow("shadow2D", "texture");
|
||||
root.renameAndWrapShadow("shadow2DLod", "textureLod");
|
||||
|
||||
if (root.containsCall("textureLodOffset")) {
|
||||
root.injectFunction("vec4 iris_textureLodOffset(sampler2D iris_tlo_s, vec2 iris_tlo_c, float iris_tlo_l, ivec2 iris_tlo_o) { return textureLod(iris_tlo_s, iris_tlo_c + vec2(iris_tlo_o) / vec2(textureSize(iris_tlo_s, int(iris_tlo_l))), iris_tlo_l); }");
|
||||
root.injectFunction("float iris_textureLodOffset(sampler2DShadow iris_tlo_s, vec3 iris_tlo_c, float iris_tlo_l, ivec2 iris_tlo_o) { return textureLod(iris_tlo_s, vec3(iris_tlo_c.xy + vec2(iris_tlo_o) / vec2(textureSize(iris_tlo_s, int(iris_tlo_l))), iris_tlo_c.z), iris_tlo_l); }");
|
||||
root.injectFunction("vec4 iris_textureLodOffset(sampler3D iris_tlo_s, vec3 iris_tlo_c, float iris_tlo_l, ivec3 iris_tlo_o) { return textureLod(iris_tlo_s, iris_tlo_c + vec3(iris_tlo_o) / vec3(textureSize(iris_tlo_s, int(iris_tlo_l))), iris_tlo_l); }");
|
||||
root.injectFunction("vec4 iris_textureLodOffset(sampler2DArray iris_tlo_s, vec3 iris_tlo_c, float iris_tlo_l, ivec2 iris_tlo_o) { return textureLod(iris_tlo_s, vec3(iris_tlo_c.xy + vec2(iris_tlo_o) / vec2(textureSize(iris_tlo_s, int(iris_tlo_l)).xy), iris_tlo_c.z), iris_tlo_l); }");
|
||||
root.injectFunction("ivec4 iris_textureLodOffset(isampler2D iris_tlo_s, vec2 iris_tlo_c, float iris_tlo_l, ivec2 iris_tlo_o) { return textureLod(iris_tlo_s, iris_tlo_c + vec2(iris_tlo_o) / vec2(textureSize(iris_tlo_s, int(iris_tlo_l))), iris_tlo_l); }");
|
||||
root.injectFunction("uvec4 iris_textureLodOffset(usampler2D iris_tlo_s, vec2 iris_tlo_c, float iris_tlo_l, ivec2 iris_tlo_o) { return textureLod(iris_tlo_s, iris_tlo_c + vec2(iris_tlo_o) / vec2(textureSize(iris_tlo_s, int(iris_tlo_l))), iris_tlo_l); }");
|
||||
root.renameFunctionCall("textureLodOffset", "iris_textureLodOffset");
|
||||
}
|
||||
|
||||
if (parameters.type == ShaderType.VERTEX) {
|
||||
root.mutateTree(tree -> {
|
||||
if (tree.children != null) {
|
||||
tree.children.removeIf(child ->
|
||||
child instanceof GLSLParser.External_declarationContext
|
||||
&& ((GLSLParser.External_declarationContext) child).declaration() != null
|
||||
&& child.getText().contains("gl_PerVertex"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (parameters.patch == Patch.ATTRIBUTES && parameters.type == ShaderType.VERTEX) {
|
||||
root.injectVariable("uniform bool angelica_ClipPlanesEnabled;");
|
||||
root.injectVariable("uniform vec4 angelica_ClipPlane[8];");
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.coderbot.iris.pipeline.transform;
|
||||
import net.coderbot.iris.gl.shader.ShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.taumc.glsl.ShaderPrinter;
|
||||
import org.taumc.glsl.Transformer;
|
||||
import org.taumc.glsl.grammar.GLSLLexer;
|
||||
import org.taumc.glsl.grammar.GLSLParser;
|
||||
@@ -109,7 +110,10 @@ public class CompatibilityTransformer {
|
||||
continue;
|
||||
}
|
||||
|
||||
prevTransformer.makeOutDeclaration(inDec.get(in), in);
|
||||
String outDeclaration = ShaderPrinter.getFormattedShader(inDec.get(in).fully_specified_type())
|
||||
+ " " + in + ";";
|
||||
prevTransformer.variable = null;
|
||||
prevTransformer.injectVariable(outDeclaration.replaceFirst("in", "out"));
|
||||
|
||||
if (!prevTransformer.hasAssigment(in)) {
|
||||
prevTransformer.initialize(inDec.get(in), in);
|
||||
@@ -126,6 +130,23 @@ public class CompatibilityTransformer {
|
||||
if (!prevTransformer.hasAssigment(in)) {
|
||||
prevTransformer.initialize(inDec.get(in), in);
|
||||
}
|
||||
} else {
|
||||
int outComp = vecComponents(outType.getText());
|
||||
int inComp = vecComponents(inType.getText());
|
||||
if (outComp < 0 || inComp < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String temp = "iris_template_" + in;
|
||||
prevTransformer.rename(in, temp);
|
||||
String newOut = ShaderPrinter.getFormattedShader(inDec.get(in).fully_specified_type())
|
||||
+ " " + in + ";";
|
||||
prevTransformer.variable = null;
|
||||
prevTransformer.injectVariable(newOut.replaceFirst("in", "out"));
|
||||
String cast = outComp < inComp
|
||||
? in + " = " + inType.getText() + "(" + temp + ", vec4(0));"
|
||||
: in + " = " + inType.getText() + "(" + temp + ");";
|
||||
prevTransformer.appendMain(cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,4 +154,13 @@ public class CompatibilityTransformer {
|
||||
prevType = type;
|
||||
}
|
||||
}
|
||||
|
||||
private static int vecComponents(String type) {
|
||||
return switch (type) {
|
||||
case "vec2" -> 2;
|
||||
case "vec3" -> 3;
|
||||
case "vec4" -> 4;
|
||||
default -> -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class CompositeDepthTransformer {
|
||||
final int type = transformer.findType("centerDepthSmooth");
|
||||
if (type != 0) {
|
||||
transformer.injectVariable("uniform sampler2D iris_centerDepthSmooth;");
|
||||
transformer.replaceExpression("centerDepthSmooth", "texture2D(iris_centerDepthSmooth, vec2(0.5)).r");
|
||||
transformer.replaceExpression("centerDepthSmooth", "texture(iris_centerDepthSmooth, vec2(0.5)).r");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,13 @@ class CoreTransformHelper {
|
||||
transformer.rename("gl_Vertex", "iris_Vertex");
|
||||
transformer.rename("gl_MultiTexCoord0", "iris_MultiTexCoord0");
|
||||
|
||||
for (int i = 1; i <= 7; i++) {
|
||||
transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)");
|
||||
}
|
||||
|
||||
transformer.replaceExpression("gl_Color", "vec4(1.0, 1.0, 1.0, 1.0)");
|
||||
transformer.replaceExpression("gl_Normal", "vec3(0.0, 0.0, 1.0)");
|
||||
|
||||
transformer.renameFunctionCall("ftransform", "iris_ftransform");
|
||||
transformer.injectFunction("vec4 iris_ftransform() { return (iris_ProjectionMatrix * iris_ModelViewMatrix) * iris_Vertex; }");
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.coderbot.iris.pipeline.transform;
|
||||
|
||||
import net.coderbot.iris.shaderpack.ProgramSource;
|
||||
import net.coderbot.iris.shaderpack.loading.ProgramId;
|
||||
|
||||
/**
|
||||
* For some reason not all shaders read from gl_MultiTexCoord0 through the texture matrix to scroll the enchant glint?
|
||||
* Maybe a modern thing but a few shaders just look wrong without it. Technically not in spec, but it looks better.
|
||||
*/
|
||||
public final class GlintScrollInjector {
|
||||
|
||||
private GlintScrollInjector() {}
|
||||
|
||||
public static boolean shouldInject(ProgramId id, ProgramSource source) {
|
||||
if (id != ProgramId.ArmorGlint || source == null) return false;
|
||||
if (!ProgramId.ArmorGlint.getSourceName().equals(source.getName())) return false;
|
||||
|
||||
final String vertex = source.getVertexSource().orElse(null);
|
||||
if (vertex == null) return false;
|
||||
// Already scrolls through the texture matrix itself
|
||||
if (vertex.contains("gl_TextureMatrix[0]")) return false;
|
||||
return vertex.contains("gl_MultiTexCoord0");
|
||||
}
|
||||
}
|
||||
@@ -104,8 +104,12 @@ public class TransformPatcher {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<PatchShaderType, String> patchAttributes(String vertex, String geometry, String tessControl, String tessEval, String fragment, InputAvailability inputs, boolean scrollGlint) {
|
||||
return transform(vertex, geometry, tessControl, tessEval, fragment, new AttributeParameters(Patch.ATTRIBUTES, geometry != null, inputs, scrollGlint));
|
||||
}
|
||||
|
||||
public static Map<PatchShaderType, String> patchAttributes(String vertex, String geometry, String tessControl, String tessEval, String fragment, InputAvailability inputs) {
|
||||
return transform(vertex, geometry, tessControl, tessEval, fragment, new AttributeParameters(Patch.ATTRIBUTES, geometry != null, inputs));
|
||||
return patchAttributes(vertex, geometry, tessControl, tessEval, fragment, inputs, false);
|
||||
}
|
||||
|
||||
public static Map<PatchShaderType, String> patchAttributes(String vertex, String geometry, String fragment, InputAvailability inputs) {
|
||||
|
||||
+6
-1
@@ -7,12 +7,14 @@ import net.coderbot.iris.shaderpack.texture.TextureStage;
|
||||
public class AttributeParameters extends Parameters {
|
||||
public final boolean hasGeometry;
|
||||
public final InputAvailability inputs;
|
||||
public final boolean scrollGlint;
|
||||
// WARNING: adding new fields requires updating hashCode and equals methods!
|
||||
|
||||
public AttributeParameters(Patch patch, boolean hasGeometry, InputAvailability inputs) {
|
||||
public AttributeParameters(Patch patch, boolean hasGeometry, InputAvailability inputs, boolean scrollGlint) {
|
||||
super(patch, null);
|
||||
this.hasGeometry = hasGeometry;
|
||||
this.inputs = inputs;
|
||||
this.scrollGlint = scrollGlint;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,6 +27,7 @@ public class AttributeParameters extends Parameters {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + (hasGeometry ? 1231 : 1237);
|
||||
result = prime * result + (scrollGlint ? 1231 : 1237);
|
||||
result = prime * result + ((inputs == null) ? 0 : inputs.hashCode());
|
||||
return result;
|
||||
}
|
||||
@@ -40,6 +43,8 @@ public class AttributeParameters extends Parameters {
|
||||
AttributeParameters other = (AttributeParameters) obj;
|
||||
if (hasGeometry != other.hasGeometry)
|
||||
return false;
|
||||
if (scrollGlint != other.scrollGlint)
|
||||
return false;
|
||||
if (inputs == null) {
|
||||
if (other.inputs != null)
|
||||
return false;
|
||||
|
||||
@@ -77,11 +77,22 @@ public class IdMap {
|
||||
private static final Pattern LEGACY_DIRECTIVE_PATTERN = Pattern.compile(
|
||||
"(?m)^\\s*#\\s*(?:if|elif|ifdef|ifndef)\\b[^\\n]*\\bMC_VERSION\\b[^\\n]*\\b10710\\b");
|
||||
|
||||
/**
|
||||
* Detects whether a pack's block.properties has a dedicated 1.7.10 section.
|
||||
*/
|
||||
public static boolean detectLegacySection(Path shaderPath) {
|
||||
String rawBlockProperties = readProperties(shaderPath, "block.properties");
|
||||
return rawBlockProperties != null && LEGACY_DIRECTIVE_PATTERN.matcher(rawBlockProperties).find();
|
||||
}
|
||||
|
||||
public static String modernFallbackMcVersion() {
|
||||
return AngelicaConfig.modernFallbackMcVersion > 0
|
||||
? String.valueOf(AngelicaConfig.modernFallbackMcVersion) : "260101";
|
||||
}
|
||||
|
||||
IdMap(Path shaderPath, ShaderPackOptions shaderPackOptions, Iterable<StringPair> environmentDefines) {
|
||||
// Check if block.properties has a dedicated 1.7.10 section
|
||||
String rawBlockProperties = readProperties(shaderPath, "block.properties");
|
||||
this.hasLegacySection = rawBlockProperties != null
|
||||
&& LEGACY_DIRECTIVE_PATTERN.matcher(rawBlockProperties).find();
|
||||
this.hasLegacySection = detectLegacySection(shaderPath);
|
||||
|
||||
Iterable<StringPair> resolvedDefines;
|
||||
if (this.hasLegacySection) {
|
||||
@@ -100,9 +111,7 @@ public class IdMap {
|
||||
}
|
||||
}
|
||||
|
||||
String modernVersion = AngelicaConfig.modernFallbackMcVersion > 0
|
||||
? String.valueOf(AngelicaConfig.modernFallbackMcVersion) : "260101";
|
||||
modernDefines.add(new StringPair("MC_VERSION", modernVersion));
|
||||
modernDefines.add(new StringPair("MC_VERSION", modernFallbackMcVersion()));
|
||||
resolvedDefines = modernDefines;
|
||||
|
||||
loadProperties(shaderPath, "block.properties", shaderPackOptions, modernDefines).ifPresent(blockProperties -> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.features.FeatureFlags;
|
||||
import net.coderbot.iris.gl.blending.BlendModeOverride;
|
||||
import net.coderbot.iris.shaderpack.include.AbsolutePackPath;
|
||||
import net.coderbot.iris.shaderpack.loading.ProgramId;
|
||||
@@ -529,7 +530,8 @@ public class ProgramSet {
|
||||
|
||||
String tessControlSource = null;
|
||||
String tessEvalSource = null;
|
||||
if (programSet.pack.hasFeature(net.coderbot.iris.features.FeatureFlags.TESSELLATION_SHADERS)) {
|
||||
if (programSet.pack.hasFeature(FeatureFlags.TESSELLATION_SHADERS)
|
||||
&& FeatureFlags.TESSELLATION_SHADERS.isUsable()) {
|
||||
AbsolutePackPath tessControlPath = directory.resolve(program + ".tcs");
|
||||
tessControlSource = sourceProvider.apply(tessControlPath);
|
||||
|
||||
@@ -547,6 +549,10 @@ public class ProgramSet {
|
||||
private static ComputeSource readComputeSource(AbsolutePackPath directory,
|
||||
Function<AbsolutePackPath, String> sourceProvider, String program,
|
||||
ProgramSet programSet) {
|
||||
if (!FeatureFlags.COMPUTE_SHADERS.isUsable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AbsolutePackPath computePath = directory.resolve(program + ".csh");
|
||||
String computeSource = sourceProvider.apply(computePath);
|
||||
|
||||
|
||||
@@ -207,8 +207,16 @@ public class ShaderPack {
|
||||
this.shaderPackOptions = new ShaderPackOptions(graph, changedConfigs);
|
||||
graph = this.shaderPackOptions.getIncludes();
|
||||
|
||||
final String mcVersionOverride = IdMap.detectLegacySection(root) ? null : IdMap.modernFallbackMcVersion();
|
||||
|
||||
List<StringPair> finalEnvironmentDefines = new ArrayList<>();
|
||||
environmentDefines.forEach(finalEnvironmentDefines::add);
|
||||
for (StringPair define : environmentDefines) {
|
||||
if (mcVersionOverride != null && "MC_VERSION".equals(define.getKey())) {
|
||||
finalEnvironmentDefines.add(new StringPair("MC_VERSION", mcVersionOverride));
|
||||
} else {
|
||||
finalEnvironmentDefines.add(define);
|
||||
}
|
||||
}
|
||||
for (FeatureFlags flag : FeatureFlags.values()) {
|
||||
boolean usable = flag.isUsable();
|
||||
Iris.logger.info("FeatureFlag {} usable: {}", flag.name(), usable);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.coderbot.iris.shaderpack.loading;
|
||||
|
||||
public enum ProgramArrayId {
|
||||
Setup(ProgramGroup.Setup, 100),
|
||||
Begin(ProgramGroup.Begin, 100),
|
||||
ShadowComposite(ProgramGroup.ShadowComposite, 99),
|
||||
Prepare(ProgramGroup.Prepare, 99),
|
||||
Deferred(ProgramGroup.Deferred, 99),
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package net.coderbot.iris.shaderpack.loading;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ProgramGroup {
|
||||
Setup("setup"),
|
||||
Begin("begin"),
|
||||
Shadow("shadow"),
|
||||
ShadowComposite("shadowcomp"),
|
||||
Prepare("prepare"),
|
||||
@@ -17,7 +22,4 @@ public enum ProgramGroup {
|
||||
this.baseName = baseName;
|
||||
}
|
||||
|
||||
public String getBaseName() {
|
||||
return baseName;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package net.coderbot.iris.shaderpack.materialmap;
|
||||
|
||||
import net.coderbot.iris.Iris;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -263,7 +263,19 @@ public final class PropertiesTokenizer {
|
||||
);
|
||||
}
|
||||
|
||||
final String[] splitStates = baseEntry.split(":");
|
||||
// Drop empty segments produced by consecutive colons (like "betterendforge::lumecorn")
|
||||
final String[] splitStates = Arrays.stream(baseEntry.split(":"))
|
||||
.filter(s -> !s.isEmpty())
|
||||
.toArray(String[]::new);
|
||||
|
||||
if (splitStates.length == 0) {
|
||||
return new ParsedBlockIdentifier(
|
||||
new NamespacedId("minecraft", baseEntry),
|
||||
Collections.emptySet(),
|
||||
Collections.emptyMap(),
|
||||
nbtProperties
|
||||
);
|
||||
}
|
||||
|
||||
// Vanilla block (minecraft namespaced)
|
||||
if (splitStates.length == 1) {
|
||||
@@ -277,7 +289,7 @@ public final class PropertiesTokenizer {
|
||||
|
||||
// Two-segment with no metas/state properties: "minecraft:stone"
|
||||
if (splitStates.length == 2
|
||||
&& !StringUtils.isNumeric(splitStates[1].substring(0, 1))
|
||||
&& !startsWithDigit(splitStates[1])
|
||||
&& !splitStates[1].contains("=")) {
|
||||
return new ParsedBlockIdentifier(
|
||||
new NamespacedId(splitStates[0], splitStates[1]),
|
||||
@@ -296,7 +308,7 @@ public final class PropertiesTokenizer {
|
||||
id = new NamespacedId("minecraft", splitStates[0]);
|
||||
statesStart = 1;
|
||||
|
||||
} else if (StringUtils.isNumeric(splitStates[1].substring(0, 1)) || splitStates[1].contains("=")) {
|
||||
} else if (startsWithDigit(splitStates[1]) || splitStates[1].contains("=")) {
|
||||
// "stone:0:something" or "stone:lit=true:something", likely will need this for snowy blocks in the future.
|
||||
id = new NamespacedId("minecraft", splitStates[0]);
|
||||
statesStart = 1;
|
||||
@@ -339,6 +351,10 @@ public final class PropertiesTokenizer {
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean startsWithDigit(String s) {
|
||||
return !s.isEmpty() && Character.isDigit(s.charAt(0));
|
||||
}
|
||||
|
||||
private static void appendCurrent(boolean inBracket, boolean readingValue,
|
||||
StringBuilder blockIdBuilder, StringBuilder nbtKey,
|
||||
StringBuilder nbtValue, char c) {
|
||||
|
||||
@@ -80,7 +80,7 @@ public class PropertiesPreprocessor {
|
||||
// Not super efficient, but this removes trailing whitespace on lines, fixing an issue with whitespace after
|
||||
// line continuations (see PreprocessorTest#testWeirdPropertiesLineContinuation)
|
||||
// Required for Voyager Shader
|
||||
source = Arrays.stream(source.split("\\R")).map(String::trim).filter(s -> !s.isEmpty())
|
||||
source = Arrays.stream(source.split("\\r\\n|\\n|\\r")).map(String::trim).filter(s -> !s.isEmpty())
|
||||
.map(line -> {
|
||||
if (line.startsWith("#")) {
|
||||
for (PreprocessorCommand command : PreprocessorCommand.values()) {
|
||||
|
||||
@@ -13,6 +13,9 @@ public class CapturedRenderingState {
|
||||
@Getter
|
||||
private float tickDelta;
|
||||
@Getter
|
||||
private int textureReloadCount;
|
||||
private Runnable textureReloadListener = null;
|
||||
@Getter
|
||||
private int currentRenderedBlockEntity;
|
||||
private Runnable blockEntityIdListener = null;
|
||||
|
||||
@@ -31,6 +34,18 @@ public class CapturedRenderingState {
|
||||
private CapturedRenderingState() {
|
||||
}
|
||||
|
||||
public void incrementTextureReloadCount() {
|
||||
this.textureReloadCount++;
|
||||
|
||||
if (this.textureReloadListener != null) {
|
||||
this.textureReloadListener.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void resetTextureReloadCount() {
|
||||
this.textureReloadCount = 0;
|
||||
}
|
||||
|
||||
public void setCurrentBlockEntity(int entity) {
|
||||
this.currentRenderedBlockEntity = entity;
|
||||
|
||||
@@ -80,5 +95,9 @@ public class CapturedRenderingState {
|
||||
return listener -> this.itemIdListener = listener;
|
||||
}
|
||||
|
||||
public ValueUpdateNotifier getTextureReloadNotifier() {
|
||||
return listener -> this.textureReloadListener = listener;
|
||||
}
|
||||
|
||||
public ValueUpdateNotifier getEntityColorNotifier() { return listener -> this.entityColorListener = listener; }
|
||||
}
|
||||
@@ -96,6 +96,12 @@ public final class CommonUniforms {
|
||||
|
||||
}, StateUpdateNotifiers.bindTextureNotifier);
|
||||
|
||||
uniforms.uniform1i("gtextureId", () -> GLStateManager.getBoundTextureForServerState(0),
|
||||
StateUpdateNotifiers.bindTextureNotifier);
|
||||
|
||||
uniforms.uniform1i("textureReloadCount", CapturedRenderingState.INSTANCE::getTextureReloadCount,
|
||||
CapturedRenderingState.INSTANCE.getTextureReloadNotifier());
|
||||
|
||||
uniforms.uniform4i("blendFunc", () -> {
|
||||
if(GLStateManager.getBlendMode().isEnabled()) {
|
||||
final BlendState blend = GLStateManager.getBlendState();
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
package net.coderbot.iris.uniforms;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.etfuturum.EtFuturumCompat;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
|
||||
import com.gtnewhorizons.angelica.render.CloudRenderer;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
import net.coderbot.iris.block_rendering.BlockMaterialMapping;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.gl.uniform.UniformHolder;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.effect.EntityLightningBolt;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import org.joml.Math;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3dc;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import java.util.List;
|
||||
@@ -21,9 +30,17 @@ public class IrisExclusiveUniforms {
|
||||
// Reusable vectors to avoid allocations every frame
|
||||
private static final Vector3d eyePositionCache = new Vector3d();
|
||||
private static final Vector3d relativeEyePositionCache = new Vector3d();
|
||||
private static final Vector3d playerLookCache = new Vector3d();
|
||||
private static final Vector3d playerBodyCache = new Vector3d();
|
||||
private static final Vector3d vehicleLookCache = new Vector3d();
|
||||
private static final Vector3d relativeVehiclePositionCache = new Vector3d();
|
||||
private static final Vector3f selectedBlockPosCache = new Vector3f();
|
||||
private static final Vector4f lightningBoltPositionCache = new Vector4f();
|
||||
private static final Vector4f ZERO_VECTOR_4f = new Vector4f(0, 0, 0, 0);
|
||||
|
||||
private static int cachedSelectedFrame = -1;
|
||||
private static int cachedSelectedBlockId;
|
||||
|
||||
public static void addIrisExclusiveUniforms(UniformHolder uniforms) {
|
||||
WorldInfoUniforms.addWorldInfoUniforms(uniforms);
|
||||
|
||||
@@ -42,6 +59,21 @@ public class IrisExclusiveUniforms {
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "relativeEyePosition", IrisExclusiveUniforms::getRelativeEyePosition);
|
||||
uniforms.uniform4f(UniformUpdateFrequency.PER_TICK, "lightningBoltPosition", IrisExclusiveUniforms::getLightningBoltPosition);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "cloudTime", IrisExclusiveUniforms::getCloudTime);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "feetInWater", IrisExclusiveUniforms::isFeetInWater);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "isRiding", IrisExclusiveUniforms::isRiding);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "vehicleInWater", IrisExclusiveUniforms::isVehicleInWater);
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_TICK, "vehicleId", IrisExclusiveUniforms::getVehicleId);
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "vehicleLookVector", IrisExclusiveUniforms::getVehicleLookVector);
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "relativeVehiclePosition", IrisExclusiveUniforms::getRelativeVehiclePosition);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "currentPlayerArmor", IrisExclusiveUniforms::getCurrentArmor);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "maxPlayerArmor", () -> 50);
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "currentSelectedBlockId", IrisExclusiveUniforms::getCurrentSelectedBlockId);
|
||||
uniforms.uniform3f(UniformUpdateFrequency.PER_FRAME, "currentSelectedBlockPos", IrisExclusiveUniforms::getCurrentSelectedBlockPos);
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "seaLevel", IrisExclusiveUniforms::getSeaLevel);
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "playerLookVector", IrisExclusiveUniforms::getPlayerLookVector);
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "playerBodyVector", IrisExclusiveUniforms::getPlayerBodyVector);
|
||||
// Target the Elytra from EFR
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "isElytraFlying", IrisExclusiveUniforms::isElytraFlying);
|
||||
}
|
||||
|
||||
private static float getCloudTime() {
|
||||
@@ -137,6 +169,149 @@ public class IrisExclusiveUniforms {
|
||||
return ZERO_VECTOR_4f;
|
||||
}
|
||||
|
||||
private static EntityLivingBase cameraEntity() {
|
||||
return Minecraft.getMinecraft().renderViewEntity;
|
||||
}
|
||||
|
||||
private static Vector3d forwardVector(Vector3d dest, float yawDeg, float pitchDeg) {
|
||||
final double yr = -yawDeg * 0.017453292 - Math.PI;
|
||||
final double pr = -pitchDeg * 0.017453292;
|
||||
final double cy = Math.cos(yr);
|
||||
final double sy = Math.sin(yr);
|
||||
final double cp = -Math.cos(pr);
|
||||
final double sp = Math.sin(pr);
|
||||
return dest.set(sy * cp, sp, cy * cp);
|
||||
}
|
||||
|
||||
private static boolean isFeetInWater() {
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
return player != null && player.isInWater();
|
||||
}
|
||||
|
||||
private static boolean isElytraFlying() {
|
||||
return EtFuturumCompat.isElytraFlying(Minecraft.getMinecraft().thePlayer);
|
||||
}
|
||||
|
||||
private static boolean isRiding() {
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
return player != null && player.ridingEntity != null;
|
||||
}
|
||||
|
||||
private static boolean isVehicleInWater() {
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
return player != null && player.ridingEntity != null && player.ridingEntity.isInWater();
|
||||
}
|
||||
|
||||
private static int getVehicleId() {
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
if (player == null || player.ridingEntity == null) return 0;
|
||||
final int id = EntityIdHelper.getEntityId(player.ridingEntity);
|
||||
return Math.max(id, 0);
|
||||
}
|
||||
|
||||
private static Vector3d getVehicleLookVector() {
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
if (player == null || player.ridingEntity == null) return vehicleLookCache.set(0, 0, 0);
|
||||
final Entity v = player.ridingEntity;
|
||||
return forwardVector(vehicleLookCache, v.rotationYaw, v.rotationPitch);
|
||||
}
|
||||
|
||||
private static Vector3d getRelativeVehiclePosition() {
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
if (player == null || player.ridingEntity == null) return relativeVehiclePositionCache.set(0, 0, 0);
|
||||
final Entity v = player.ridingEntity;
|
||||
final float delta = CapturedRenderingState.INSTANCE.getTickDelta();
|
||||
final double vx = v.prevPosX + (v.posX - v.prevPosX) * delta;
|
||||
final double vy = v.prevPosY + (v.posY - v.prevPosY) * delta;
|
||||
final double vz = v.prevPosZ + (v.posZ - v.prevPosZ) * delta;
|
||||
// Match Angelica's relativeEyePosition convention (entity - camera).
|
||||
final Vector3dc cam = CameraUniforms.getUnshiftedCameraPosition();
|
||||
return relativeVehiclePositionCache.set(vx - cam.x(), vy - cam.y(), vz - cam.z());
|
||||
}
|
||||
|
||||
private static float getCurrentArmor() {
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
if (mc.thePlayer == null || !mc.playerController.gameIsSurvivalOrAdventure()) {
|
||||
return -1;
|
||||
}
|
||||
return mc.thePlayer.getTotalArmorValue() / 50.0f;
|
||||
}
|
||||
|
||||
private static Vector3d getPlayerLookVector() {
|
||||
final EntityLivingBase e = cameraEntity();
|
||||
if (e == null) return playerLookCache.set(0, 0, 0);
|
||||
final float delta = CapturedRenderingState.INSTANCE.getTickDelta();
|
||||
final float yaw = e.prevRotationYaw + (e.rotationYaw - e.prevRotationYaw) * delta;
|
||||
final float pitch = e.prevRotationPitch + (e.rotationPitch - e.prevRotationPitch) * delta;
|
||||
return forwardVector(playerLookCache, yaw, pitch);
|
||||
}
|
||||
|
||||
private static Vector3d getPlayerBodyVector() {
|
||||
final EntityLivingBase e = cameraEntity();
|
||||
if (e == null) return playerBodyCache.set(0, 0, 0);
|
||||
return forwardVector(playerBodyCache, e.renderYawOffset, 0.0f);
|
||||
}
|
||||
|
||||
private static int getSeaLevel() {
|
||||
// 1.7.10 has no per-world sea level accessor, best to guess 63?
|
||||
return 63;
|
||||
}
|
||||
|
||||
private static void updateSelectedBlock() {
|
||||
final int frame = SystemTimeUniforms.COUNTER.getAsInt();
|
||||
if (frame == cachedSelectedFrame) {
|
||||
return;
|
||||
}
|
||||
cachedSelectedFrame = frame;
|
||||
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
final MovingObjectPosition hit = mc.objectMouseOver;
|
||||
if (mc.theWorld == null || hit == null || hit.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) {
|
||||
cachedSelectedBlockId = 0;
|
||||
selectedBlockPosCache.set(-256.0f, -256.0f, -256.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
final Vector3dc cam = CameraUniforms.getUnshiftedCameraPosition();
|
||||
selectedBlockPosCache.set(
|
||||
(float) ((hit.blockX + 0.5) - cam.x()),
|
||||
(float) ((hit.blockY + 0.5) - cam.y()),
|
||||
(float) ((hit.blockZ + 0.5) - cam.z()));
|
||||
|
||||
final Block block = mc.theWorld.getBlock(hit.blockX, hit.blockY, hit.blockZ);
|
||||
if (block == null || block.isAir(mc.theWorld, hit.blockX, hit.blockY, hit.blockZ)) {
|
||||
cachedSelectedBlockId = 0;
|
||||
return;
|
||||
}
|
||||
final Reference2ObjectMap<Block, Int2IntMap> blockMetaMatches = BlockRenderingSettings.INSTANCE.getBlockMetaMatches();
|
||||
if (blockMetaMatches == null) {
|
||||
cachedSelectedBlockId = 0;
|
||||
return;
|
||||
}
|
||||
final Int2IntMap metaMap = blockMetaMatches.get(block);
|
||||
if (metaMap == null) {
|
||||
cachedSelectedBlockId = 0;
|
||||
return;
|
||||
}
|
||||
final int meta = mc.theWorld.getBlockMetadata(hit.blockX, hit.blockY, hit.blockZ);
|
||||
cachedSelectedBlockId = Math.max(BlockMaterialMapping.resolveId(metaMap, meta), 0);
|
||||
}
|
||||
|
||||
private static int getCurrentSelectedBlockId() {
|
||||
updateSelectedBlock();
|
||||
return cachedSelectedBlockId;
|
||||
}
|
||||
|
||||
private static Vector3f getCurrentSelectedBlockPos() {
|
||||
updateSelectedBlock();
|
||||
return selectedBlockPosCache;
|
||||
}
|
||||
|
||||
private static int worldHeight() {
|
||||
final WorldClient level = Minecraft.getMinecraft().theWorld;
|
||||
return (level != null && level.provider != null) ? level.provider.getHeight() : 256;
|
||||
}
|
||||
|
||||
public static class WorldInfoUniforms {
|
||||
public static void addWorldInfoUniforms(UniformHolder uniforms) {
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "bedrockLevel", () -> 0);
|
||||
@@ -148,14 +323,8 @@ public class IrisExclusiveUniforms {
|
||||
return 192.0;
|
||||
}
|
||||
});
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "heightLimit", () -> {
|
||||
final WorldClient level = Minecraft.getMinecraft().theWorld;
|
||||
if (level != null && level.provider != null) {
|
||||
return level.provider.getHeight();
|
||||
} else {
|
||||
return 256;
|
||||
}
|
||||
});
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "heightLimit", IrisExclusiveUniforms::worldHeight);
|
||||
uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "logicalHeightLimit", IrisExclusiveUniforms::worldHeight);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_FRAME, "hasCeiling", () -> {
|
||||
final WorldClient level = Minecraft.getMinecraft().theWorld;
|
||||
if (level != null && level.provider != null) {
|
||||
|
||||
@@ -3,7 +3,10 @@ package net.coderbot.iris.uniforms;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.gl.uniform.UniformHolder;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
import org.joml.Vector2i;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
@@ -16,19 +19,47 @@ public final class SystemTimeUniforms {
|
||||
public static final Timer TIMER = new Timer();
|
||||
public static final FrameCounter COUNTER = new FrameCounter();
|
||||
|
||||
private static LocalDateTime cachedDateTime = LocalDateTime.now();
|
||||
private static long cachedDateTimeAtMs = 0L;
|
||||
|
||||
private SystemTimeUniforms() {
|
||||
}
|
||||
|
||||
private static LocalDateTime dateTimeSnapshot() {
|
||||
final long now = System.currentTimeMillis();
|
||||
if (now - cachedDateTimeAtMs >= 50L) {
|
||||
cachedDateTime = LocalDateTime.now();
|
||||
cachedDateTimeAtMs = now;
|
||||
}
|
||||
return cachedDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes system time uniforms available to the given program
|
||||
*
|
||||
* @param uniforms the program to make the uniforms available to
|
||||
*/
|
||||
public static void addSystemTimeUniforms(UniformHolder uniforms) {
|
||||
final Vector3i date = new Vector3i();
|
||||
final Vector3i time = new Vector3i();
|
||||
final Vector2i yearTime = new Vector2i();
|
||||
uniforms
|
||||
.uniform1i(UniformUpdateFrequency.PER_FRAME, "frameCounter", COUNTER)
|
||||
.uniform1f(UniformUpdateFrequency.PER_FRAME, "frameTime", TIMER::getLastFrameTime)
|
||||
.uniform1f(UniformUpdateFrequency.PER_FRAME, "frameTimeCounter", TIMER::getFrameTimeCounter);
|
||||
.uniform1f(UniformUpdateFrequency.PER_FRAME, "frameTimeCounter", TIMER::getFrameTimeCounter)
|
||||
.uniform3i(UniformUpdateFrequency.PER_TICK, "currentDate", () -> {
|
||||
final LocalDateTime dt = dateTimeSnapshot();
|
||||
return date.set(dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth());
|
||||
})
|
||||
.uniform3i(UniformUpdateFrequency.PER_TICK, "currentTime", () -> {
|
||||
final LocalDateTime dt = dateTimeSnapshot();
|
||||
return time.set(dt.getHour(), dt.getMinute(), dt.getSecond());
|
||||
})
|
||||
.uniform2i(UniformUpdateFrequency.PER_TICK, "currentYearTime", () -> {
|
||||
final LocalDateTime dt = dateTimeSnapshot();
|
||||
final int elapsed = ((dt.getDayOfYear() - 1) * 86400) + (dt.getHour() * 3600) + (dt.getMinute() * 60) + dt.getSecond();
|
||||
return yearTime.set(elapsed, (dt.toLocalDate().lengthOfYear() * 86400) - elapsed);
|
||||
});
|
||||
}
|
||||
|
||||
public static void addFloatFrameMod8Uniform(UniformHolder uniforms) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.mojang.InteractionHand;
|
||||
import com.gtnewhorizons.angelica.shadercompat.ShaderGlint;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
@@ -63,6 +64,7 @@ public class MixinItemRenderer {
|
||||
private void iris$glintStart(CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.GLINT);
|
||||
ShaderGlint.beginGlint();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,5 +77,6 @@ public class MixinItemRenderer {
|
||||
)
|
||||
private void iris$glintEnd(CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
ShaderGlint.endGlint();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.shadercompat.ShaderGlint;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
@@ -41,6 +42,7 @@ public class MixinRenderItem {
|
||||
private void iris$glintStart(CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.GLINT);
|
||||
ShaderGlint.beginGlint();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,5 +55,6 @@ public class MixinRenderItem {
|
||||
)
|
||||
private void iris$glintEnd(CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
ShaderGlint.endGlint();
|
||||
}
|
||||
}
|
||||
+3
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.shadercompat.ShaderGlint;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
@@ -80,6 +81,7 @@ public class MixinRendererLivingEntity {
|
||||
)
|
||||
private void iris$glintStart(CallbackInfo ci) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.GLINT);
|
||||
ShaderGlint.beginGlint();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +94,7 @@ public class MixinRendererLivingEntity {
|
||||
)
|
||||
private void iris$glintEnd(CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
ShaderGlint.endGlint();
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Hook into TextureManger to increment the reload count.
|
||||
*/
|
||||
@Mixin(TextureManager.class)
|
||||
public class MixinTextureManager_ReloadCount {
|
||||
|
||||
@Inject(method = "onResourceManagerReload", at = @At("TAIL"))
|
||||
private void angelica$bumpTextureReloadCount(IResourceManager resourceManager, CallbackInfo ci) {
|
||||
CapturedRenderingState.INSTANCE.incrementTextureReloadCount();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user