aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/Features.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/ChromaConfig.java62
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt8
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaFontRenderer.kt66
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShader.kt47
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShaderManager.kt38
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/hooks/FontRendererHook.kt135
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorFontRenderer.java12
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorMinecraft.java13
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java75
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinPatcherFontRendererHook.java21
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt11
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt55
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt124
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt87
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt45
-rw-r--r--src/main/resources/assets/skyhanni/shaders/chroma.fsh43
-rw-r--r--src/main/resources/assets/skyhanni/shaders/chroma.vsh15
-rw-r--r--src/main/resources/mixins.skyhanni.json7
20 files changed, 866 insertions, 5 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index edd5d62b5..4e4cbc68d 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -331,7 +331,7 @@ class SkyHanniMod {
loadModule(TestExportTools)
loadModule(ItemClickData())
// loadModule(Year300RaffleEvent)
- loadModule(MinecraftData())
+ loadModule(MinecraftData)
loadModule(TitleManager())
loadModule(ItemTipHelper())
loadModule(RenderLivingEntityHelper())
diff --git a/src/main/java/at/hannibal2/skyhanni/config/Features.java b/src/main/java/at/hannibal2/skyhanni/config/Features.java
index 95ffa7f6c..f5916cda8 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/Features.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/Features.java
@@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod;
import at.hannibal2.skyhanni.config.features.About;
import at.hannibal2.skyhanni.config.features.BazaarConfig;
import at.hannibal2.skyhanni.config.features.ChatConfig;
+import at.hannibal2.skyhanni.config.features.ChromaConfig;
import at.hannibal2.skyhanni.config.features.CombatConfig;
import at.hannibal2.skyhanni.config.features.CommandsConfig;
import at.hannibal2.skyhanni.config.features.CrimsonIsleConfig;
@@ -68,6 +69,10 @@ public class Features extends Config {
public GUIConfig gui = new GUIConfig();
@Expose
+ @Category(name = "Chroma", desc = "Settings for Chroma text. (Credit to SBA)")
+ public ChromaConfig chroma = new ChromaConfig();
+
+ @Expose
@Category(name = "Chat", desc = "Change how the chat looks.")
public ChatConfig chat = new ChatConfig();
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/ChromaConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/ChromaConfig.java
new file mode 100644
index 000000000..80c40cd98
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/ChromaConfig.java
@@ -0,0 +1,62 @@
+package at.hannibal2.skyhanni.config.features;
+
+import at.hannibal2.skyhanni.SkyHanniMod;
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorButton;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorDropdown;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorInfoText;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorSlider;
+import io.github.moulberry.moulconfig.annotations.ConfigOption;
+
+public class ChromaConfig {
+
+ @Expose
+ @ConfigOption(name = "Chroma Preview", desc = "§fPlease star the mod on GitHub!")
+ @ConfigEditorInfoText(infoTitle = "Only In SkyBlock")
+ public boolean chromaPreview = false;
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "Toggle for SkyHanni's chroma. (Disables Patcher's Optimized Font Renderer while enabled)")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean enabled = false;
+
+ @Expose
+ @ConfigOption(name = "Chroma Size", desc = "Change the size of each color in the chroma.")
+ @ConfigEditorSlider(minValue = 1f, maxValue = 100f, minStep = 1f)
+ public float chromaSize = 30f;
+
+ @Expose
+ @ConfigOption(name = "Chroma Speed", desc = "Change how fast the chroma animation moves.")
+ @ConfigEditorSlider(minValue = 0.5f, maxValue = 20f, minStep = 0.5f)
+ public float chromaSpeed = 6f;
+
+ @Expose
+ @ConfigOption(name = "Chroma Saturation", desc = "Change the saturation of the chroma.")
+ @ConfigEditorSlider(minValue = 0f, maxValue = 1f, minStep = 0.01f)
+ public float chromaSaturation = 0.75f;
+
+ @Expose
+ @ConfigOption(name = "Chroma Direction", desc = "Change the slant and direction of the chroma.")
+ @ConfigEditorDropdown(values = {"Forward + Right", "Forward + Left", "Backward + Right", "Backward + Left"})
+ public int chromaDirection = 0;
+
+ @ConfigOption(name = "Reset to Default", desc = "Resets all chroma settings to the default.")
+ @ConfigEditorButton(buttonText = "Reset")
+ public Runnable resetSettings = this::resetChromaSettings;
+
+ @Expose
+ @ConfigOption(name = "Everything Chroma", desc = "Renders §4§l§oALL §r§7text in chroma. (Some enchants may appear white with SBA enchant parsing)")
+ @ConfigEditorBoolean
+ public boolean allChroma = false;
+
+ private void resetChromaSettings() {
+ SkyHanniMod.getFeature().chroma.chromaSize = 30f;
+ SkyHanniMod.getFeature().chroma.chromaSpeed = 6f;
+ SkyHanniMod.getFeature().chroma.chromaSaturation = 0.75f;
+ SkyHanniMod.getFeature().chroma.allChroma = false;
+ SkyHanniMod.getFeature().chroma.chromaDirection = 0;
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt b/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
index a09380357..da9497d08 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
@@ -18,7 +18,7 @@ import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
-class MinecraftData {
+object MinecraftData {
@SubscribeEvent(receiveCanceled = true)
fun onSoundPacket(event: PacketEvent.ReceiveEvent) {
@@ -64,13 +64,13 @@ class MinecraftData {
}
}
- private var tick = 0
+ var totalTicks = 0
@SubscribeEvent
fun onTick(event: TickEvent.ClientTickEvent) {
Minecraft.getMinecraft().thePlayer ?: return
- tick++
- LorenzTickEvent(tick).postAndCatch()
+ totalTicks++
+ LorenzTickEvent(totalTicks).postAndCatch()
}
@SubscribeEvent
diff --git a/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaFontRenderer.kt b/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaFontRenderer.kt
new file mode 100644
index 000000000..981b7b33a
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaFontRenderer.kt
@@ -0,0 +1,66 @@
+package at.hannibal2.skyhanni.features.chroma
+
+import at.hannibal2.skyhanni.utils.ColorUtils
+import at.hannibal2.skyhanni.utils.shader.ShaderHelper
+import net.minecraft.client.renderer.GlStateManager
+import org.lwjgl.opengl.GL11
+
+/**
+ * Class to handle chroma font rendering
+ *
+ * Modified class from SkyblockAddons
+ *
+ * Credit: [DrawStateFontRenderer.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/utils/draw/DrawStateFontRenderer.java)
+ */
+class ChromaFontRenderer(private val baseColor: Int) {
+
+ private var chromaOn = false
+
+ fun startChroma() {
+ chromaOn = true
+ }
+
+ fun endChroma() {
+ chromaOn = false
+ }
+
+ fun loadChromaEnv() {
+ if (chromaOn) {
+ newChromaEnv()
+ }
+ }
+
+ fun restoreChromaEnv() {
+ if (ShaderHelper.areShadersSupported()) {
+ if (!chromaOn) ChromaShaderManager.end()
+ }
+ }
+
+ fun newChromaEnv() : ChromaFontRenderer {
+ if (ShaderHelper.areShadersSupported()) {
+ ChromaShaderManager.begin()
+ GlStateManager.shadeModel(GL11.GL_SMOOTH)
+ }
+ return this
+ }
+
+ fun bindActualColor() : ChromaFontRenderer {
+ GlStateManager.color(
+ ColorUtils.getRed(baseColor).toFloat() / 255f,
+ ColorUtils.getGreen(baseColor).toFloat() / 255f,
+ ColorUtils.getBlue(baseColor).toFloat() / 255f,
+ ColorUtils.getAlpha(baseColor).toFloat() / 255f
+ )
+ return this
+ }
+
+ fun endChromaEnv() : ChromaFontRenderer {
+ if (ShaderHelper.areShadersSupported()) {
+ ChromaShaderManager.end()
+ GlStateManager.shadeModel(GL11.GL_FLAT)
+ }
+ return this
+ }
+
+ fun getChromaState() = chromaOn
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShader.kt b/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShader.kt
new file mode 100644
index 000000000..00215b032
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShader.kt
@@ -0,0 +1,47 @@
+package at.hannibal2.skyhanni.features.chroma
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.MinecraftData
+import at.hannibal2.skyhanni.mixins.transformers.AccessorMinecraft
+import at.hannibal2.skyhanni.utils.shader.Shader
+import at.hannibal2.skyhanni.utils.shader.Uniform
+import net.minecraft.client.Minecraft
+
+/**
+ * Modified from SkyblockAddons
+ *
+ * Credit: [ChromaShader.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/chroma/ChromaShader.java)
+ */
+object ChromaShader : Shader("chroma", "chroma") {
+
+ val INSTANCE: ChromaShader
+ get() = this
+
+ override fun registerUniforms() {
+ registerUniform(Uniform.UniformType.FLOAT, "chromaSize") {
+ SkyHanniMod.feature.chroma.chromaSize * (Minecraft.getMinecraft().displayWidth / 100f)
+ }
+ registerUniform(Uniform.UniformType.FLOAT, "timeOffset") {
+ var ticks = (MinecraftData.totalTicks / 2) + (Minecraft.getMinecraft() as AccessorMinecraft).timer.renderPartialTicks
+
+ ticks = when (SkyHanniMod.feature.chroma.chromaDirection) {
+ 0, 2 -> ticks
+ 1, 3 -> -ticks
+ else -> ticks
+ }
+
+ val chromaSpeed = SkyHanniMod.feature.chroma.chromaSpeed / 360f
+ ticks * chromaSpeed
+ }
+ registerUniform(Uniform.UniformType.FLOAT, "saturation") {
+ SkyHanniMod.feature.chroma.chromaSaturation
+ }
+ registerUniform(Uniform.UniformType.BOOL, "forwardDirection") {
+ when (SkyHanniMod.feature.chroma.chromaDirection) {
+ 0, 1 -> true
+ 2, 3 -> false
+ else -> true
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShaderManager.kt b/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShaderManager.kt
new file mode 100644
index 000000000..ccf0ec21e
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/chroma/ChromaShaderManager.kt
@@ -0,0 +1,38 @@
+package at.hannibal2.skyhanni.features.chroma
+
+import at.hannibal2.skyhanni.utils.shader.ShaderManager
+
+/**
+ * Object to handle enabling / disabling the chroma shader when rendering text
+ *
+ * Modified from SkyblockAddons
+ *
+ * Credit: [MulticolorShaderManager.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/core/chroma/MulticolorShaderManager.java)
+ */
+object ChromaShaderManager {
+
+ private var chromaEnabled = false
+
+ fun begin() {
+ disable()
+ enable()
+ }
+
+ fun end() {
+ disable()
+ }
+
+ private fun enable() {
+ if (!chromaEnabled) {
+ chromaEnabled = true
+ ShaderManager.enableShader("chroma")
+ }
+ }
+
+ private fun disable() {
+ if (chromaEnabled) {
+ chromaEnabled = false
+ ShaderManager.disableShader()
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/hooks/FontRendererHook.kt b/src/main/java/at/hannibal2/skyhanni/mixins/hooks/FontRendererHook.kt
new file mode 100644
index 000000000..808406946
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/hooks/FontRendererHook.kt
@@ -0,0 +1,135 @@
+package at.hannibal2.skyhanni.mixins.hooks
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.features.chroma.ChromaFontRenderer
+import at.hannibal2.skyhanni.mixins.transformers.AccessorFontRenderer
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+
+/**
+ * Object to handle chroma font states from handler methods from MixinFontRenderer
+ *
+ * Modified from SkyblockAddons
+ *
+ * Credit: [FontRendererHook.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/asm/hooks/FontRendererHook.java)
+ */
+object FontRendererHook {
+ private var CHROMA_COLOR: Int = -0x1
+ private val DRAW_CHROMA = ChromaFontRenderer(CHROMA_COLOR)
+ private var CHROMA_COLOR_SHADOW: Int = -0xAAAAAB
+ private val DRAW_CHROMA_SHADOW = ChromaFontRenderer(CHROMA_COLOR_SHADOW)
+
+ private var currentDrawState: ChromaFontRenderer? = null
+ private var previewChroma = false
+
+ /**
+ * Setups the [ChromaFontRenderer][at.hannibal2.skyhanni.features.chroma.ChromaFontRenderer] for rendering text
+ * in chroma. This should only be used when you don't have control over the color code a string uses, or it
+ * doesn't make sense to add §Z color code to a string.
+ *
+ * If you do have control over the color code, you can prepend the string with §Z instead.
+ *
+ * **Usage:**
+ *
+ * Surround string render call with this method and [endChromaFont].
+ * ```
+ * FontRendererHook.setupChromaFont()
+ * // render string call(s) here...
+ * FontRendererHook.endChromaFont()
+ * ```
+ *
+ * Note: This only works if the string render call ends up using
+ * [FontRenderer#drawString()][net.minecraft.client.gui.FontRenderer.drawString] rather than a custom font renderer
+ *
+ */
+ fun setupChromaFont() {
+ DRAW_CHROMA.startChroma()
+ DRAW_CHROMA_SHADOW.startChroma()
+ }
+
+ /**
+ * See [setupChromaFont]
+ */
+ fun endChromaFont() {
+ DRAW_CHROMA.endChroma()
+ DRAW_CHROMA_SHADOW.endChroma()
+ }
+
+ @JvmStatic
+ fun beginChromaRendering(text: String, shadow: Boolean) {
+ if (!LorenzUtils.inSkyBlock) return
+ if (!SkyHanniMod.feature.chroma.enabled) return
+
+ if (text == "§fPlease star the mod on GitHub!") {
+ previewChroma = true
+ setupChromaFont()
+ }
+
+ val alpha = (Minecraft.getMinecraft().fontRendererObj as AccessorFontRenderer).alpha
+ if (shadow) {
+ currentDrawState = DRAW_CHROMA_SHADOW
+ CHROMA_COLOR_SHADOW = ((255 * alpha).toInt() shl 24 or 0x555555)
+ } else {
+ currentDrawState = DRAW_CHROMA
+ CHROMA_COLOR = ((255 * alpha).toInt() shl 24 or 0xFFFFFF)
+ }
+
+ // Best feature ngl
+ if (SkyHanniMod.feature.chroma.allChroma) {
+ // Handles setting the base color of text when they don't use color codes i.e. MoulConfig
+ if (shadow) {
+ GlStateManager.color(0.33f, 0.33f, 0.33f, 1f)
+ } else {
+ GlStateManager.color(1f, 1f, 1f, 1f)
+ }
+ setupChromaFont()
+ }
+
+ currentDrawState?.loadChromaEnv()
+ }
+
+ @JvmStatic
+ fun toggleChromaOn() {
+ if (!LorenzUtils.inSkyBlock) return
+
+ currentDrawState?.newChromaEnv()?.bindActualColor()
+ }
+
+ @JvmStatic
+ fun forceWhiteColorCode(i1: Int) : Int {
+ if (!SkyHanniMod.feature.chroma.enabled) return i1
+
+ val drawState = currentDrawState ?: return i1
+ if (drawState.getChromaState()) {
+ if (i1 < 16) {
+ return 15
+ }
+ }
+
+ return i1
+ }
+
+ @JvmStatic
+ fun restoreChromaState() {
+ if (!SkyHanniMod.feature.chroma.enabled) return
+ if (!LorenzUtils.inSkyBlock) return
+
+ currentDrawState?.restoreChromaEnv()
+ }
+
+ @JvmStatic
+ fun endChromaRendering() {
+ if (!SkyHanniMod.feature.chroma.enabled) return
+ if (!LorenzUtils.inSkyBlock) return
+
+ if (previewChroma) {
+ previewChroma = false
+ endChromaFont()
+ }
+
+ if (SkyHanniMod.feature.chroma.allChroma) endChromaFont()
+
+ currentDrawState?.endChromaEnv()
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorFontRenderer.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorFontRenderer.java
new file mode 100644
index 000000000..e20462d1a
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorFontRenderer.java
@@ -0,0 +1,12 @@
+package at.hannibal2.skyhanni.mixins.transformers;
+
+import net.minecraft.client.gui.FontRenderer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(FontRenderer.class)
+public interface AccessorFontRenderer {
+
+ @Accessor("alpha")
+ float getAlpha();
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorMinecraft.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorMinecraft.java
new file mode 100644
index 000000000..24074f296
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorMinecraft.java
@@ -0,0 +1,13 @@
+package at.hannibal2.skyhanni.mixins.transformers;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.Timer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(Minecraft.class)
+public interface AccessorMinecraft {
+
+ @Accessor("timer")
+ Timer getTimer();
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java
new file mode 100644
index 000000000..cf357eb74
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java
@@ -0,0 +1,75 @@
+package at.hannibal2.skyhanni.mixins.transformers;
+
+import at.hannibal2.skyhanni.SkyHanniMod;
+import at.hannibal2.skyhanni.mixins.hooks.FontRendererHook;
+import net.minecraft.client.gui.FontRenderer;
+import org.spongepowered.asm.lib.Opcodes;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.*;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+@Mixin(FontRenderer.class)
+public abstract class MixinFontRenderer {
+
+ /**
+ * Inject call to {@link FontRendererHook#beginChromaRendering(String, boolean)} as first call
+ */
+ @Inject(method = "renderStringAtPos", at = @At("HEAD"))
+ public void beginRenderString(String text, boolean shadow, CallbackInfo ci) {
+ FontRendererHook.beginChromaRendering(text, shadow);
+ }
+
+ /**
+ * Modify color code constant to add Z color code
+ */
+ @ModifyConstant(method = "renderStringAtPos", constant = @Constant(stringValue = "0123456789abcdefklmnor"))
+ public String insertZColorCode(String constant) {
+ if (!SkyHanniMod.getFeature().chroma.enabled) return constant;
+ return "0123456789abcdefklmnorz";
+ }
+
+ /**
+ * Inject call to {@link FontRendererHook#restoreChromaState()} after 1st and 3rd fontrenderer.italicStyle = ___ call
+ */
+ @Inject(method = "renderStringAtPos", at = {
+ @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/gui/FontRenderer;italicStyle:Z", ordinal = 0, shift = At.Shift.AFTER),
+ @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/gui/FontRenderer;italicStyle:Z", ordinal = 2, shift = At.Shift.AFTER)})
+ public void insertRestoreChromaState(CallbackInfo ci) {
+ FontRendererHook.restoreChromaState();
+ }
+
+ @Shadow
+ protected abstract void resetStyles();
+
+ /**
+ * Inject call to {@link FontRendererHook#toggleChromaOn()} to check for Z color code index and if so,
+ * reset styles and toggle chroma on
+ */
+ @Inject(method = "renderStringAtPos", at = @At(value = "INVOKE", target = "Ljava/lang/String;indexOf(I)I", ordinal = 0, shift = At.Shift.BY, by = 2), locals = LocalCapture.CAPTURE_FAILHARD)
+ public void toggleChromaCondition(String text, boolean shadow, CallbackInfo ci, int i, char c0, int i1) {
+ if (!SkyHanniMod.getFeature().chroma.enabled) return;
+ if (i1 == 22) {
+ this.resetStyles();
+ FontRendererHook.toggleChromaOn();
+ }
+ }
+
+ /**
+ * Replace all color codes (when chroma is enabled) to white so chroma renders uniformly and at best brightness
+ */
+ @ModifyVariable(method = "renderStringAtPos", at = @At(value = "INVOKE", target = "Ljava/lang/String;indexOf(I)I", ordinal = 0, shift = At.Shift.BY, by = 2), ordinal = 1)
+ public int forceWhiteColorCode(int i1) {
+ return FontRendererHook.forceWhiteColorCode(i1);
+ }
+
+ /**
+ * Inject call to {@link FontRendererHook#endChromaRendering()} to turn off chroma rendering after entire
+ * string has been rendered
+ */
+ @Inject(method = "renderStringAtPos", at = @At("RETURN"))
+ public void insertEndOfString(String text, boolean shadow, CallbackInfo ci) {
+ FontRendererHook.endChromaRendering();
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinPatcherFontRendererHook.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinPatcherFontRendererHook.java
new file mode 100644
index 000000000..7c585b725
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinPatcherFontRendererHook.java
@@ -0,0 +1,21 @@
+package at.hannibal2.skyhanni.mixins.transformers;
+
+import at.hannibal2.skyhanni.SkyHanniMod;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Pseudo;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Pseudo
+@Mixin(targets = "club.sk1er.patcher.hooks.FontRendererHook")
+public class MixinPatcherFontRendererHook {
+
+ @Inject(method = "renderStringAtPos(Ljava/lang/String;Z)Z", at = @At("HEAD"), cancellable = true)
+ public void overridePatcherFontRenderer(String string, boolean shadow, CallbackInfoReturnable<Boolean> cir) {
+ if (SkyHanniMod.getFeature().chroma.enabled) {
+ cir.cancel();
+ cir.setReturnValue(false);
+ }
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt
new file mode 100644
index 000000000..076afc0c4
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt
@@ -0,0 +1,11 @@
+package at.hannibal2.skyhanni.utils
+
+object ColorUtils {
+ fun getRed(colour: Int) = colour shr 16 and 0xFF
+
+ fun getGreen(colour: Int) = colour shr 8 and 0xFF
+
+ fun getBlue(colour: Int) = colour and 0xFF
+
+ fun getAlpha(colour: Int) = colour shr 24 and 0xFF
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt
new file mode 100644
index 000000000..f198f7e7a
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt
@@ -0,0 +1,55 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.shader.ShaderLinkHelper
+import org.apache.commons.lang3.StringUtils
+import org.lwjgl.opengl.GL11
+import java.util.function.Supplier
+
+/**
+ * Superclass for shader objects to compile and attach vertex and fragment shaders to the shader program
+ *
+ * Modified class from SkyblockAddons
+ *
+ * Credit: [Shader.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/Shader.java)
+ */
+abstract class Shader(vertex: String, fragment: String) {
+
+ var shaderProgram: Int = ShaderLinkHelper.getStaticShaderLinkHelper().createProgram()
+ private val uniforms: MutableList<Uniform<*>> = mutableListOf()
+
+ init {
+ val vertexShaderID = ShaderManager.loadShader(ShaderType.VERTEX, vertex)
+ ShaderManager.attachShader(shaderProgram, vertexShaderID)
+ val fragmentShaderID = ShaderManager.loadShader(ShaderType.FRAGMENT, fragment)
+ ShaderManager.attachShader(shaderProgram, fragmentShaderID)
+
+ ShaderHelper.glLinkProgram(shaderProgram)
+
+ val linkStatus = ShaderHelper.glGetProgrami(shaderProgram, ShaderHelper.GL_LINK_STATUS)
+ if (linkStatus == GL11.GL_FALSE) {
+ LorenzUtils.consoleLog(
+ "Error occurred when linking program with Vertex Shader: $vertex and Fragment Shader: $fragment : " +
+ StringUtils.trim(ShaderHelper.glGetProgramInfoLog(shaderProgram, 1024))
+ )
+ }
+
+ this.registerUniforms()
+ }
+
+ abstract fun registerUniforms()
+
+ fun updateUniforms() {
+ for (uniform in uniforms) {
+ uniform.update()
+ }
+ }
+
+ fun enable() = ShaderHelper.glUseProgram(shaderProgram)
+
+ fun disable() = ShaderHelper.glUseProgram(0)
+
+ fun <T> registerUniform(uniformType: Uniform.UniformType<T>, name: String, uniformValuesSupplier: Supplier<T>) {
+ uniforms.add(Uniform(this, uniformType, name, uniformValuesSupplier))
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt
new file mode 100644
index 000000000..e554a4098
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt
@@ -0,0 +1,124 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import org.lwjgl.opengl.*
+
+/**
+ * Class to check shaders support, OpenGL capabilities, and shader helper functions
+ *
+ * Modified class from SkyblockAddons
+ *
+ * Credit: [ShaderHelper.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/ShaderHelper.java)
+ */
+class ShaderHelper {
+ companion object {
+ private var SHADERS_SUPPORTED: Boolean
+
+ private var USING_ARB_SHADERS: Boolean
+
+ var GL_LINK_STATUS: Int
+ var GL_COMPILE_STATUS: Int
+ var GL_VERTEX_SHADER: Int
+ var GL_FRAGMENT_SHADER: Int
+
+ init {
+ val capabilities: ContextCapabilities = GLContext.getCapabilities()
+
+ // Check OpenGL 2.0 Capabilities
+ val openGL20supported = capabilities.OpenGL20
+ SHADERS_SUPPORTED = openGL20supported ||
+ capabilities.GL_ARB_vertex_shader &&
+ capabilities.GL_ARB_fragment_shader &&
+ capabilities.GL_ARB_shader_objects
+
+ var log = "Shaders are"
+ if (!SHADERS_SUPPORTED) log += " not"
+ log += " available. "
+
+ if (SHADERS_SUPPORTED) {
+ if (capabilities.OpenGL20) {
+ log += "OpenGL 2.0 is supported. "
+ USING_ARB_SHADERS = false
+ GL_LINK_STATUS = GL20.GL_LINK_STATUS
+ GL_COMPILE_STATUS = GL20.GL_COMPILE_STATUS
+ GL_VERTEX_SHADER = GL20.GL_VERTEX_SHADER
+ GL_FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER
+ } else {
+ log += "ARB_shader_objects, ARB_vertex_shader, and ARB_fragment_shader are supported. "
+ USING_ARB_SHADERS = true
+ GL_LINK_STATUS = ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB
+ GL_COMPILE_STATUS = ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB
+ GL_VERTEX_SHADER = ARBVertexShader.GL_VERTEX_SHADER_ARB
+ GL_FRAGMENT_SHADER = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB
+ }
+ } else {
+ log += "OpenGL 2.0 is not supported and ARB_shader_objects, ARB_vertex_shader, and ARB_fragment_shader are not supported."
+ USING_ARB_SHADERS = false
+ GL_LINK_STATUS = GL11.GL_FALSE
+ GL_COMPILE_STATUS = GL11.GL_FALSE
+ GL_VERTEX_SHADER = GL11.GL_FALSE
+ GL_FRAGMENT_SHADER = GL11.GL_FALSE
+ }
+
+ LorenzUtils.consoleLog(log)
+ }
+
+ fun glLinkProgram(program: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glLinkProgramARB(program) else GL20.glLinkProgram(program)
+ }
+
+ fun glGetProgramInfoLog(program: Int, maxLength: Int) : String {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetInfoLogARB(program, maxLength) else GL20.glGetProgramInfoLog(program, maxLength)
+ }
+
+ fun glGetProgrami(program: Int, pname: Int) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetObjectParameteriARB(program, pname) else GL20.glGetProgrami(program, pname)
+ }
+
+ fun glUseProgram(program: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glUseProgramObjectARB(program) else GL20.glUseProgram(program)
+ }
+
+ fun glAttachShader(program: Int, shaderIn: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glAttachObjectARB(program, shaderIn) else GL20.glAttachShader(program, shaderIn)
+ }
+
+ fun glCreateShader(type: Int) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glCreateShaderObjectARB(type) else GL20.glCreateShader(type)
+ }
+
+ fun glShaderSource(shader: Int, source: CharSequence) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glShaderSourceARB(shader, source) else GL20.glShaderSource(shader, source)
+ }
+
+ fun glCompileShader(shader: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glCompileShaderARB(shader) else GL20.glCompileShader(shader)
+ }
+
+ fun glGetShaderi(shader: Int, pname: Int) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetObjectParameteriARB(shader, pname) else GL20.glGetShaderi(shader, pname)
+ }
+
+ fun glGetShaderInfoLog(shader: Int, maxLength: Int) : String {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetInfoLogARB(shader, maxLength) else GL20.glGetShaderInfoLog(shader, maxLength)
+ }
+
+ fun glDeleteShader(shader: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glDeleteObjectARB(shader) else GL20.glDeleteShader(shader)
+ }
+
+ fun glUniform1f(location: Int, v0: Float) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glUniform1fARB(location, v0) else GL20.glUniform1f(location, v0)
+ }
+
+ fun glUniform3f(location: Int, v0: Float, v1: Float, v2: Float) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glUniform3fARB(location, v0, v1, v2) else GL20.glUniform3f(location, v0, v1, v2)
+ }
+
+ fun glGetUniformLocation(program: Int, name: CharSequence) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetUniformLocationARB(program, name) else GL20.glGetUniformLocation(program, name)
+ }
+
+ fun areShadersSupported() = SHADERS_SUPPORTED
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt
new file mode 100644
index 000000000..e7eb48f11
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt
@@ -0,0 +1,87 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import at.hannibal2.skyhanni.features.chroma.ChromaShader
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.util.ResourceLocation
+import org.apache.commons.lang3.StringUtils
+import java.io.BufferedReader
+import java.io.InputStreamReader
+
+/**
+ * Object to handle shaders for SkyHanni
+ */
+object ShaderManager {
+
+ /**
+ * For any future shaders add the object instance in this enum and
+ * in the when expression
+ */
+ enum class Shaders(val shader: Shader) {
+ CHROMA(ChromaShader.INSTANCE);
+
+ companion object {
+ fun getShaderInstance(shaderName: String) : Shader? = when (shaderName) {
+ "chroma" -> CHROMA.shader
+ else -> {
+ null
+ }
+ }
+ }
+ }
+
+ private val shaders: MutableMap<String, Shader> = mutableMapOf()
+ private var activeShader: Shader? = null
+
+ fun enableShader(shaderName: String) {
+ var shader = shaders[shaderName]
+
+ if (shader == null) {
+ shader = Shaders.getShaderInstance(shaderName)
+ if (shader == null) return
+ shaders[shaderName] = shader
+ }
+
+ activeShader = shader
+ shader.enable()
+ shader.updateUniforms()
+ }
+
+ fun attachShader(shaderProgram: Int, shaderID: Int) {
+ ShaderHelper.glAttachShader(shaderProgram, shaderID)
+ }
+
+ fun disableShader() {
+ if (activeShader == null) return
+
+ activeShader?.disable()
+ activeShader = null
+ }
+
+ fun loadShader(type: ShaderType, fileName: String) : Int {
+ val resourceLocation = ResourceLocation("skyhanni:shaders/$fileName${type.extension}")
+
+ val source = StringBuilder()
+
+ val inputStream = Minecraft.getMinecraft().resourceManager.getResource(resourceLocation).inputStream
+ BufferedReader(InputStreamReader(inputStream)).forEachLine {
+ source.append(it).append("\n")
+ }
+
+ val shaderID = ShaderHelper.glCreateShader(type.shaderType)
+ ShaderHelper.glShaderSource(shaderID, source.toString())
+ ShaderHelper.glCompileShader(shaderID)
+
+ if (ShaderHelper.glGetShaderi(shaderID, ShaderHelper.GL_COMPILE_STATUS) == 0) {
+ LorenzUtils.consoleLog("Error occurred when compiling shader $fileName${type.extension} : " +
+ StringUtils.trim(ShaderHelper.glGetShaderInfoLog(shaderID, 1024)))
+ }
+
+ return shaderID
+ }
+}
+
+enum class ShaderType(val extension: String, val shaderType: Int) {
+ VERTEX(".vsh", ShaderHelper.GL_VERTEX_SHADER),
+ FRAGMENT(".fsh", ShaderHelper.GL_FRAGMENT_SHADER)
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt
new file mode 100644
index 000000000..e87ea3b22
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt
@@ -0,0 +1,45 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import java.util.*
+import java.util.function.Supplier
+
+/**
+ * Class to handle shader uniform types
+ *
+ * Modified from SkyblockAddons
+ *
+ * Credit: [Uniform.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/Uniform.java)
+ */
+class Uniform<T>(
+ shader: Shader,
+ private val uniformType: UniformType<T>,
+ val name: String,
+ private val uniformValuesSupplier: Supplier<T>
+) {
+
+ class UniformType<T> {
+ companion object {
+ val FLOAT: UniformType<Float> = UniformType()
+ val VEC3: UniformType<FloatArray> = UniformType()
+ val BOOL: UniformType<Boolean> = UniformType()
+ }
+ }
+
+ private val uniformID: Int = ShaderHelper.glGetUniformLocation(shader.shaderProgram, name)
+ private var previousUniformValue: T? = null
+
+ fun update() {
+ val newUniformValue: T = uniformValuesSupplier.get()
+ if (!Objects.deepEquals(previousUniformValue, newUniformValue)) {
+ when (uniformType) {
+ UniformType.FLOAT -> ShaderHelper.glUniform1f(uniformID, (newUniformValue as Float))
+ UniformType.VEC3 -> {
+ val values = newUniformValue as FloatArray
+ ShaderHelper.glUniform3f(uniformID, values[0], values[1], values[2])
+ }
+ UniformType.BOOL -> ShaderHelper.glUniform1f(uniformID, if (newUniformValue as Boolean) 1f else 0f)
+ }
+ previousUniformValue = newUniformValue
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/resources/assets/skyhanni/shaders/chroma.fsh b/src/main/resources/assets/skyhanni/shaders/chroma.fsh
new file mode 100644
index 000000000..7b48a62f9
--- /dev/null
+++ b/src/main/resources/assets/skyhanni/shaders/chroma.fsh
@@ -0,0 +1,43 @@
+// Chroma Fragment Shader
+// Modified from SkyblockAddons
+// Credit: https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/resources/assets/skyblockaddons/shaders/program/chroma_screen_textured.fsh
+
+#version 120
+
+uniform float chromaSize;
+uniform float timeOffset;
+uniform float saturation;
+uniform bool forwardDirection;
+
+uniform sampler2D outTexture;
+
+varying vec2 outTextureCoords;
+varying vec4 outColor;
+
+float rgb2b(vec3 rgb) {
+ return max(max(rgb.r, rgb.g), rgb.b);
+}
+
+vec3 hsb2rgb_smooth(vec3 c) {
+ vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
+ rgb = rgb * rgb * (3.0 - 2.0 * rgb); // Cubic smoothing
+ return c.z * mix(vec3(1.0), rgb, c.y);
+}
+
+void main() {
+ vec4 originalColor = texture2D(outTexture, outTextureCoords) * outColor;
+
+ // Determine the direction chroma moves
+ float fragCoord;
+ if (forwardDirection) {
+ fragCoord = gl_FragCoord.x - gl_FragCoord.y;
+ } else {
+ fragCoord = gl_FragCoord.x + gl_FragCoord.y;
+ }
+
+ // The hue takes in account the position, chroma settings, and time
+ float hue = mod(((fragCoord) / chromaSize) - timeOffset, 1.0);
+
+ // Set the color to use the new hue & original saturation/value/alpha values
+ gl_FragColor = vec4(hsb2rgb_smooth(vec3(hue, saturation, rgb2b(originalColor.rgb))), originalColor.a);
+} \ No newline at end of file
diff --git a/src/main/resources/assets/skyhanni/shaders/chroma.vsh b/src/main/resources/assets/skyhanni/shaders/chroma.vsh
new file mode 100644
index 000000000..5f5030d07
--- /dev/null
+++ b/src/main/resources/assets/skyhanni/shaders/chroma.vsh
@@ -0,0 +1,15 @@
+// Chroma Vertex Shader
+// Credit: https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/resources/assets/skyblockaddons/shaders/program/chroma_screen_textured.vsh
+
+#version 120
+
+varying vec2 outTextureCoords;
+varying vec4 outColor;
+
+void main() {
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+
+ // Pass the color & texture coords to the fragment shader
+ outColor = gl_Color;
+ outTextureCoords = gl_MultiTexCoord0.st;
+}
diff --git a/src/main/resources/mixins.skyhanni.json b/src/main/resources/mixins.skyhanni.json
index 8daf1a330..aa1b61873 100644
--- a/src/main/resources/mixins.skyhanni.json
+++ b/src/main/resources/mixins.skyhanni.json
@@ -2,6 +2,9 @@
"package": "at.hannibal2.skyhanni.mixins.transformers",
"refmap": "mixins.skyhanni.refmap.json",
"compatibilityLevel": "JAVA_8",
+ "injectors": {
+ "maxShiftBy": 2
+ },
"mixins": [
"AccessorChatComponentText",
"AccessorGuiPlayerTabOverlay",
@@ -13,6 +16,7 @@
"MixinItemStack",
"MixinNetHandlerPlayClient",
"MixinNetworkManager",
+ "MixinPatcherFontRendererHook",
"MixinRendererLivingEntity",
"MixinRenderGlobal",
"MixinRenderItem",
@@ -22,10 +26,13 @@
"renderer.MixinRendererLivingEntity"
],
"client": [
+ "AccessorFontRenderer",
"AccessorGuiEditSign",
"AccessorKeyBinding",
+ "AccessorMinecraft",
"CustomRenderGlobal",
"MixinEntityRenderer",
+ "MixinFontRenderer",
"MixinGuiChat",
"MixinGuiIngame",
"MixinGuiPlayerTabOverlay",