Compare commits

..
10 Commits
Author SHA1 Message Date
Jason Mitchell 03d908d658 Update readme and version detectors (#1893) 2026-06-27 15:47:32 -07:00
Eclipse-Sol 76bf19c8f6 Majority shader fixes (#1868) 2026-06-27 14:48:51 -07:00
Eclipse-Sol b27834cbd9 Narrow and make damage overlay a config option (#1886) 2026-06-27 10:12:39 -07:00
sisyphussyandJason Mitchell eb0ecb0483 Fix deps (#1888)
Co-authored-by: Jason Mitchell <[email protected]>
2026-06-27 10:11:30 -07:00
Caedis 9acb0e67a7 feat: add smooth zoom option (#1890) 2026-06-27 09:57:21 -07:00
Jason Mitchell f4f9b56b17 End portal fix (#1891) 2026-06-27 09:56:21 -07:00
Midnight145 2196439e6c ClientEvent framework (primarily written for LiteloaderLoader) (#1843) 2026-06-25 20:13:18 -07:00
RedNicStone dd68c64239 Fix map rendering issue in xaero's map mods (#1880) 2026-06-21 14:13:11 -07:00
Jason Mitchell 0decc515e4 Fix universium shader (#1877) 2026-06-18 23:42:21 -07:00
tiffit b3e1e89c88 Add new CTM mode "compact_expanded" to generate textures on runtime (#1840)
* Rewrite compact CTM to generate the textures ahead of time

* fix animated textures not working

* only interpolate if notfine is enabled

* some bugfixes

* bring back old compact ctm and make a new compact_expanded

* bug fixes
2026-06-18 12:04:45 +03:00
72 changed files with 1348 additions and 163 deletions

No files matched your search

+1 -1
View File
@@ -23,7 +23,7 @@ Targets GL 3.3+ core profile
# Required Dependencies
* [UniMixins](https://github.com/LegacyModdingMC/UniMixins/releases) >= 0.1.23
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.9.0
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.11.19
* NOTE: Some mods are not required, but a specific version is required if present - see: `Permanent Incompatibilities` below.
# Known (temporary) Incompatibilities
+4 -1
View File
@@ -76,7 +76,7 @@ dependencies {
// Iris Shaders
compileOnly('org.jetbrains:annotations:26.0.2')
api("com.github.GTNewHorizons:GTNHLib:0.11.4:dev")
api("com.github.GTNewHorizons:GTNHLib:0.11.19:dev")
shadowImplementation(project(":glsm")) { transitive = false }
shadowImplementation(project(":lwjgl3-backend")) { transitive = false }
@@ -173,6 +173,9 @@ dependencies {
testImplementation('org.junit.platform:junit-platform-launcher')
testImplementation('com.tngtech.archunit:archunit-junit5:1.4.1')
testRuntimeOnly("it.unimi.dsi:fastutil:8.5.18")
testRuntimeOnly("org.joml:joml:1.10.8")
}
}
+2
View File
@@ -96,6 +96,8 @@ dependencies {
// Deps (normally from MC) - compile only, but needed at test runtime
compileOnly("com.google.guava:guava:${property("guavaVersion")}")
testRuntimeOnly("com.google.guava:guava:${property("guavaVersion")}")
testRuntimeOnly("it.unimi.dsi:fastutil:${property("fastutilVersion")}")
testRuntimeOnly("org.joml:joml:${property("jomlVersion")}") { isTransitive = false }
// Test
testImplementation(sourceSets["stubs"].output)
+3 -1
View File
@@ -4,7 +4,9 @@ celeritasVersion = 2.5.3-GTNH
lombokVersion = 1.18.42
log4jVersion = 2.0-beta9
guavaVersion = 18.0
gtnhlibVersion = 0.10.0
gtnhlibVersion = 0.11.19
fastutilVersion = 8.5.18
jomlVersion = 1.10.8
glslTransformLibVersion = 0.2.0-26.g5ee7d96-GTNH
antlr4RuntimeVersion = 4.13.2
jcppVersion = 1.4.14
@@ -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;
@@ -187,6 +188,14 @@ public class GLStateManager {
private static boolean dirtyTexCoordAttrib;
private static boolean dirtyLightmapAttrib = true;
private static boolean unit23TexCoordSetDuringDraw = false;
public static boolean consumeUnit23TexCoordSetDuringDraw() {
boolean v = unit23TexCoordSetDuringDraw;
unit23TexCoordSetDuringDraw = false;
return v;
}
// vertexFlags bits mark attribs the VBO already supplies; FFP supplies the rest via u_Current* uniforms.
// Skip the backend vertexAttrib call in either case.
public static void flushDeferredVertexAttribs(boolean hasColor, boolean hasNormal, boolean hasTexCoord, boolean hasLightmap) {
@@ -1605,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;
@@ -2158,6 +2172,7 @@ public class GLStateManager {
}
public static void glBegin(int mode) {
unit23TexCoordSetDuringDraw = false;
if (DisplayListManager.isRecording()) {
ImmediateModeRecorder.begin(mode);
return;
@@ -5325,6 +5340,9 @@ public class GLStateManager {
} else {
final int unit = target - GL13.GL_TEXTURE0;
if (unit >= 2 && unit < 4) {
if (DisplayListManager.isRecording() || ImmediateModeRecorder.isDrawing()) {
unit23TexCoordSetDuringDraw = true;
}
ShaderManager.setCurrentTexCoord(unit, s, t, 0.0f, 1.0f);
}
}
@@ -6030,15 +6048,15 @@ public class GLStateManager {
}
public static void glUniform1(int location, IntBuffer values) {
if (values.remaining() >= 1) RENDER_BACKEND.uniform1i(location, values.get(values.position()));
RENDER_BACKEND.uniform1iv(location, values);
}
public static void glUniform2(int location, FloatBuffer values) {
if (values.remaining() >= 2) RENDER_BACKEND.uniform2f(location, values.get(values.position()), values.get(values.position() + 1));
RENDER_BACKEND.uniform2(location, values);
}
public static void glUniform2(int location, IntBuffer values) {
if (values.remaining() >= 2) RENDER_BACKEND.uniform2i(location, values.get(values.position()), values.get(values.position() + 1));
RENDER_BACKEND.uniform2iv(location, values);
}
public static void glUniform3(int location, FloatBuffer values) {
@@ -6046,7 +6064,7 @@ public class GLStateManager {
}
public static void glUniform3(int location, IntBuffer values) {
if (values.remaining() >= 3) RENDER_BACKEND.uniform3i(location, values.get(values.position()), values.get(values.position() + 1), values.get(values.position() + 2));
RENDER_BACKEND.uniform3iv(location, values);
}
public static void glUniform4(int location, FloatBuffer values) {
@@ -6054,7 +6072,7 @@ public class GLStateManager {
}
public static void glUniform4(int location, IntBuffer values) {
if (values.remaining() >= 4) RENDER_BACKEND.uniform4i(location, values.get(values.position()), values.get(values.position() + 1), values.get(values.position() + 2), values.get(values.position() + 3));
RENDER_BACKEND.uniform4iv(location, values);
}
public static void glUniformMatrix2(int location, boolean transpose, FloatBuffer matrices) {
@@ -822,6 +822,11 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
GL20.glUniform4i(location, v0, v1, v2, v3);
}
@Override
public void uniform2(int location, FloatBuffer value) {
GL20.glUniform2(location, value);
}
@Override
public void uniform3(int location, FloatBuffer value) {
GL20.glUniform3(location, value);
@@ -832,6 +837,26 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
GL20.glUniform4(location, value);
}
@Override
public void uniform1iv(int location, IntBuffer value) {
GL20.glUniform1(location, value);
}
@Override
public void uniform2iv(int location, IntBuffer value) {
GL20.glUniform2(location, value);
}
@Override
public void uniform3iv(int location, IntBuffer value) {
GL20.glUniform3(location, value);
}
@Override
public void uniform4iv(int location, IntBuffer value) {
GL20.glUniform4(location, value);
}
@Override
public void uniformMatrix3(int location, boolean transpose, FloatBuffer value) {
GL20.glUniformMatrix3(location, transpose, value);
@@ -201,8 +201,13 @@ public abstract class RenderBackend {
public abstract void uniform3i(int location, int v0, int v1, int v2);
public abstract void uniform4f(int location, float v0, float v1, float v2, float v3);
public abstract void uniform4i(int location, int v0, int v1, int v2, int v3);
public abstract void uniform2(int location, FloatBuffer value);
public abstract void uniform3(int location, FloatBuffer value);
public abstract void uniform4(int location, FloatBuffer value);
public abstract void uniform1iv(int location, IntBuffer value);
public abstract void uniform2iv(int location, IntBuffer value);
public abstract void uniform3iv(int location, IntBuffer value);
public abstract void uniform4iv(int location, IntBuffer value);
public abstract void uniformMatrix3(int location, boolean transpose, FloatBuffer value);
public abstract void uniformMatrix4(int location, boolean transpose, FloatBuffer value);
public void uniformMatrix2(int location, boolean transpose, FloatBuffer matrices) {}
@@ -78,7 +78,7 @@ public final class FragmentShaderGenerator {
private static void emitTextureSampling(StringBuilder sb, FragmentKey key) {
for (int i = 0; i < key.nrEnabledUnits(); i++) {
if (!key.unitEnabled(i)) continue;
sb.append(" vec4 tex").append(i).append("Color = texture(u_Sampler").append(i).append(", v_TexCoord").append(i).append(".st);\n");
sb.append(" vec4 tex").append(i).append("Color = textureProj(u_Sampler").append(i).append(", v_TexCoord").append(i).append(");\n");
}
}
@@ -49,6 +49,7 @@ public final class VertexKey {
private static final int BIT_WIDE_LINE = 36;
// Per-unit texmat enable: bits 37-40 (unit 0..3). Unit 1 is the lightmap matrix.
private static final int BIT_UNIT_TEXMAT_BASE = 37;
private static final int BIT_UNIT23_UV_FROM_UNIT0 = 41;
public static final int TG_NONE = 0;
public static final int TG_OBJ_LINEAR = 1;
@@ -85,6 +86,7 @@ public final class VertexKey {
public boolean hasVertexNormal() { return bit(BIT_HAS_VERTEX_NORMAL); }
public boolean hasVertexTexCoord() { return bit(BIT_HAS_VERTEX_TEX); }
public boolean hasVertexLightmap() { return bit(BIT_HAS_VERTEX_LIGHTMAP); }
public boolean unit23UvFromUnit0() { return bit(BIT_UNIT23_UV_FROM_UNIT0); }
/** Color material mode (CM_AMBIENT, CM_DIFFUSE, CM_SPECULAR, CM_EMISSION, CM_AMBIENT_AND_DIFFUSE). Only meaningful when colorMaterialEnabled(). */
public int colorMaterialMode() { return (int)((packed >> BIT_COLOR_MAT_MODE) & 0x7); }
@@ -213,6 +215,10 @@ public final class VertexKey {
if (hasTexCoord) bits |= (1L << BIT_HAS_VERTEX_TEX);
if (hasLightmap) bits |= (1L << BIT_HAS_VERTEX_LIGHTMAP);
if (GLStateManager.consumeUnit23TexCoordSetDuringDraw() && hasTexCoord) {
bits |= (1L << BIT_UNIT23_UV_FROM_UNIT0);
}
if (GLStateManager.anyClipPlaneEnabled()) {
bits |= (1L << BIT_CLIP_PLANES);
}
@@ -106,8 +106,8 @@ public final class VertexShaderGenerator {
if (key.unitTexCoordEnabled(0) && !key.hasVertexTexCoord()) {
sb.append("uniform vec4 u_CurrentTexCoord0;\n");
}
if (key.unitTexCoordEnabled(2)) sb.append("uniform vec4 u_CurrentTexCoord2;\n");
if (key.unitTexCoordEnabled(3)) sb.append("uniform vec4 u_CurrentTexCoord3;\n");
if (key.unitTexCoordEnabled(2) && !key.unit23UvFromUnit0()) sb.append("uniform vec4 u_CurrentTexCoord2;\n");
if (key.unitTexCoordEnabled(3) && !key.unit23UvFromUnit0()) sb.append("uniform vec4 u_CurrentTexCoord3;\n");
if (key.lightmapEnabled() && !key.hasVertexLightmap()) {
sb.append("uniform vec2 u_CurrentLightmapCoord;\n");
@@ -363,8 +363,10 @@ public final class VertexShaderGenerator {
for (int i = 2; i < VertexKey.MAX_UNITS; i++) {
if (!key.unitTexCoordEnabled(i)) continue;
final String src = "u_CurrentTexCoord" + i;
if (key.unitTexMatEnabled(i)) {
final String src = key.unit23UvFromUnit0()
? "vec4(a_TexCoord0, 0.0, 1.0)"
: "u_CurrentTexCoord" + i;
if (!key.unit23UvFromUnit0() && key.unitTexMatEnabled(i)) {
sb.append(" v_TexCoord").append(i).append(" = u_TextureMatrix").append(i).append(" * ").append(src).append(";\n");
} else {
sb.append(" v_TexCoord").append(i).append(" = ").append(src).append(";\n");
@@ -383,7 +385,7 @@ public final class VertexShaderGenerator {
emitTexGenComponent(sb, key.texGenModeS(), "s", "S", key);
emitTexGenComponent(sb, key.texGenModeT(), "t", "T", key);
emitTexGenComponent(sb, key.texGenModeR(), "r", "R", key);
emitTexGenComponent(sb, key.texGenModeR(), "p", "R", key);
emitTexGenComponent(sb, key.texGenModeQ(), "q", "Q", key);
// Always apply texture matrix when texgen is active (forced on in VertexKey)
@@ -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);
}
@@ -0,0 +1,103 @@
package com.gtnewhorizons.angelica.glsm;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(GLSMCoreExtension.class)
class ArrayUniformUploadGLTest {
private static int compile(int type, String src) {
final int s = GL20.glCreateShader(type);
GL20.glShaderSource(s, src);
GL20.glCompileShader(s);
assertEquals(GL11.GL_TRUE, GL20.glGetShaderi(s, GL20.GL_COMPILE_STATUS), () -> "shader compile failed: " + GL20.glGetShaderInfoLog(s, 4096));
return s;
}
private static int link(String vs, String fs) {
final int v = compile(GL20.GL_VERTEX_SHADER, vs);
final int f = compile(GL20.GL_FRAGMENT_SHADER, fs);
final int p = GL20.glCreateProgram();
GL20.glAttachShader(p, v);
GL20.glAttachShader(p, f);
GL20.glLinkProgram(p);
assertEquals(GL11.GL_TRUE, GL20.glGetProgrami(p, GL20.GL_LINK_STATUS), () -> "link failed: " + GL20.glGetProgramInfoLog(p, 4096));
GL20.glDeleteShader(v);
GL20.glDeleteShader(f);
return p;
}
private static final String VS = "#version 330 core\nvoid main(){ gl_Position = vec4(0.0); }\n";
@Test
void glUniform2FloatBufferUploadsWholeArray() {
// Runtime index keeps the whole array active so element locations stay queryable.
final String fs = "#version 330 core\n"
+ "uniform vec2 cosmicuvs[10];\n"
+ "uniform int idx;\n"
+ "out vec4 o;\n"
+ "void main(){ o = vec4(cosmicuvs[idx], cosmicuvs[(idx+1)%10]); }\n";
final int p = link(VS, fs);
try {
GL20.glUseProgram(p);
final FloatBuffer buf = BufferUtils.createFloatBuffer(20);
for (int i = 0; i < 20; i++) buf.put(i + 1.0f); // 1..20, all distinct, all non-zero
buf.flip();
GLStateManager.glUniform2(GL20.glGetUniformLocation(p, "cosmicuvs"), buf);
final FloatBuffer read = BufferUtils.createFloatBuffer(2);
for (int i = 0; i < 10; i++) {
final int loc = GL20.glGetUniformLocation(p, "cosmicuvs[" + i + "]");
assertTrue(loc >= 0, "element " + i + " optimized out");
read.clear();
GL20.glGetUniform(p, loc, read);
assertEquals(2 * i + 1.0f, read.get(0), 0.0f, "cosmicuvs[" + i + "].x");
assertEquals(2 * i + 2.0f, read.get(1), 0.0f, "cosmicuvs[" + i + "].y");
}
} finally {
GL20.glUseProgram(0);
GL20.glDeleteProgram(p);
}
}
@Test
void glUniform1IntBufferUploadsWholeArray() {
final String fs = "#version 330 core\n"
+ "uniform int vals[4];\n"
+ "uniform int idx;\n"
+ "out vec4 o;\n"
+ "void main(){ o = vec4(float(vals[idx])); }\n";
final int p = link(VS, fs);
try {
GL20.glUseProgram(p);
final IntBuffer buf = BufferUtils.createIntBuffer(4);
buf.put(11).put(22).put(33).put(44).flip();
GLStateManager.glUniform1(GL20.glGetUniformLocation(p, "vals"), buf);
final IntBuffer read = BufferUtils.createIntBuffer(1);
final int[] expect = {11, 22, 33, 44};
for (int i = 0; i < 4; i++) {
final int loc = GL20.glGetUniformLocation(p, "vals[" + i + "]");
assertTrue(loc >= 0, "element " + i + " optimized out");
read.clear();
GL20.glGetUniform(p, loc, read);
assertEquals(expect[i], read.get(0), "vals[" + i + "]");
}
} finally {
GL20.glUseProgram(0);
GL20.glDeleteProgram(p);
}
}
}
+4
View File
@@ -34,6 +34,10 @@ repositories {
name = "GTNH Maven"
url = uri("https://nexus.gtnewhorizons.com/repository/public/")
}
maven {
name = "Minecraft Libraries"
url = uri("https://libraries.minecraft.net")
}
maven {
name = "Forge"
url = uri("https://maven.minecraftforge.net/")
@@ -866,6 +866,11 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
GL20C.glUniform4i(location, v0, v1, v2, v3);
}
@Override
public void uniform2(int location, FloatBuffer value) {
GL20C.glUniform2fv(location, value);
}
@Override
public void uniform3(int location, FloatBuffer value) {
GL20C.glUniform3fv(location, value);
@@ -876,6 +881,26 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
GL20C.glUniform4fv(location, value);
}
@Override
public void uniform1iv(int location, IntBuffer value) {
GL20C.glUniform1iv(location, value);
}
@Override
public void uniform2iv(int location, IntBuffer value) {
GL20C.glUniform2iv(location, value);
}
@Override
public void uniform3iv(int location, IntBuffer value) {
GL20C.glUniform3iv(location, value);
}
@Override
public void uniform4iv(int location, IntBuffer value) {
GL20C.glUniform4iv(location, value);
}
@Override
public void uniformMatrix3(int location, boolean transpose, FloatBuffer value) {
GL20C.glUniformMatrix3fv(location, transpose, value);
@@ -16,7 +16,7 @@ import static com.gtnewhorizons.angelica.AngelicaMod.MOD_ID;
name = "Angelica",
version = Tags.VERSION,
dependencies = """
required-after:gtnhlib@[0.8.21,);\
required-after:gtnhlib@[0.11.19,);\
before:lwjgl3ify@[1.5.3,);\
after:hodgepodge@[2.4.4,);\
after:CodeChickenCore@[1.2.0,);\
@@ -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;
}
}
}
@@ -357,8 +357,13 @@ public class AngelicaConfig {
@Config.RequiresMcRestart
public static boolean disableErrorChecks;
@Config.Comment("Fixes various issues with entity overlays, such as z-fighting, damage animations and eyes.")
@Config.Comment("Fixes various issues with entity overlays, such as z-fighting and eyes.")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public static boolean entityOverlayFixes;
@Config.Comment("Swap the vanilla damage overlay with one similar to modern. Fixes specific issues with z-fighting.")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public static boolean entityModernDamageOverlay;
}
@@ -0,0 +1,36 @@
package com.gtnewhorizons.angelica.event;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraftforge.eventbus.api.bus.EventBus;
import net.minecraftforge.eventbus.api.event.MutableEvent;
public class ClientEvent extends MutableEvent {
public static final EventBus<ClientEvent> BUS = EventBus.create(ClientEvent.class);
public final ClientEventType event;
public final EntityRenderer renderer;
public final float partialTicks;
private ClientEvent(ClientEventType event) {
this.event = event;
this.renderer = null;
this.partialTicks = 0;
}
private ClientEvent(ClientEventType event, EntityRenderer renderer, float partialTicks) {
this.event = event;
this.renderer = renderer;
this.partialTicks = partialTicks;
}
public static void post(ClientEventType event, EntityRenderer renderer, float partialTicks) {
if (!BUS.hasListeners()) return;
BUS.post(new ClientEvent(event, renderer, partialTicks));
}
public static void post(ClientEventType event) {
if (!BUS.hasListeners()) return;
BUS.post(new ClientEvent(event));
}
}
@@ -0,0 +1,8 @@
package com.gtnewhorizons.angelica.event;
public enum ClientEventType {
PRE_RENDER_GUI,
PRE_RENDER_HUD,
POST_RENDER_HUD,
ON_TICK,
}
@@ -6,11 +6,12 @@ import com.gtnewhorizon.gtnhlib.client.renderer.postprocessing.CustomFramebuffer
import com.gtnewhorizon.gtnhlib.client.renderer.postprocessing.SharedDepthFramebuffer;
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IVertexArrayObject;
import com.gtnewhorizon.gtnhlib.client.renderer.vao.VertexBufferType;
import com.gtnewhorizon.gtnhlib.client.renderer.vbo.IVertexBuffer;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.compat.holoinventory.HoloInventoryReflectionCompat;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.event.ClientEvent;
import com.gtnewhorizons.angelica.event.ClientEventType;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
import com.gtnewhorizons.angelica.mixins.interfaces.GuiIngameAccessor;
@@ -65,6 +66,8 @@ public class HUDCaching {
}
public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, float partialTicks, boolean hasScreen, int mouseX, int mouseY) {
ClientEvent.post(ClientEventType.PRE_RENDER_GUI, renderer, partialTicks);
ClientEvent.post(ClientEventType.PRE_RENDER_HUD, renderer, partialTicks);
if (ModStatus.isXaerosMinimapLoaded && ingame instanceof GuiIngameForge) {
// this used to be called by asming into renderGameOverlay, but we removed it
XaeroMinimapCore.beforeIngameGuiRender(partialTicks);
@@ -78,6 +81,7 @@ public class HUDCaching {
if (!AngelicaConfig.hudCachingActive || mc.displayWidth < 16 || mc.displayHeight < 16) {
ingame.renderGameOverlay(partialTicks, hasScreen, mouseX, mouseY);
ClientEvent.post(ClientEventType.POST_RENDER_HUD, renderer, partialTicks);
return;
}
@@ -170,6 +174,8 @@ public class HUDCaching {
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
mc.getTextureManager().bindTexture(Gui.icons);
ClientEvent.post(ClientEventType.POST_RENDER_HUD, renderer, partialTicks);
}
/**
@@ -120,7 +120,10 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
"Missing dependency: Angelica requires GTNHLib! Download: https://modrinth.com/mod/gtnhlib"),
new DependencyVerifier.Check(
"/com/gtnewhorizon/gtnhlib/client/renderer/VertexCallbackManager.class",
"GTNHLib is outdated: Angelica requires GTNHLib 0.10.0 or newer! Download: https://modrinth.com/mod/gtnhlib")
"GTNHLib is outdated: Angelica requires GTNHLib 0.10.0 or newer! Download: https://modrinth.com/mod/gtnhlib"),
new DependencyVerifier.Check(
"/it/unimi/dsi/fastutil/objects/ObjectBooleanBiConsumer.class",
"GTNHLib is outdated: Angelica requires GTNHLib 0.11.19 or newer (fastutil 8.5.18+)! Download: https://modrinth.com/mod/gtnhlib")
));
} catch (RuntimeException ex) {
fatalDependencyError(ex.getMessage());
@@ -64,7 +64,15 @@ public enum Mixins implements IMixins {
.addExcludedMod(TargetedMod.CUSTOM_PLAYER_MODELS)
.addClientMixins(
"angelica.bugfixes.MixinRendererLivingEntity_EyeDepth"
, "angelica.bugfixes.MixinRendererLivingEntity_OverlayTint"
)
),
ANGELICA_DAMAGE_OVERLAY(new MixinBuilder()
.setPhase(Phase.EARLY)
.setApplyIf(() -> AngelicaConfig.entityModernDamageOverlay)
.addExcludedMod(TargetedMod.CUSTOM_PLAYER_MODELS)
.addClientMixins(
"angelica.bugfixes.MixinRendererLivingEntity_OverlayTint"
)
),
@@ -290,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);
}
}
@@ -4,6 +4,8 @@ import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.InputEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import jss.notfine.core.Settings;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
@@ -19,6 +21,13 @@ public class Zoom {
@Getter
private static float zoom = ZOOM_DEFAULT;
public static final float ZOOM_SMOOTH_SNAP_EPSILON = 0.001F;
@Getter
private static float currentZoom = 1.0F;
private static long zoomLerpLastNano = 0L;
@Getter
private static final KeyBinding zoomKey = new KeyBinding("Zoom", 0, "key.categories.misc");
@@ -38,6 +47,29 @@ public class Zoom {
zoom = MathHelper.clamp_float((float) (zoom * Math.pow(ZOOM_STEP, Integer.signum(eventDWheel))), ZOOM_MIN, ZOOM_MAX);
}
public static void updateZoomLerp() {
final long now = System.nanoTime();
float dt = zoomLerpLastNano == 0L ? 0.0F : (now - zoomLerpLastNano) / 1.0e9F;
zoomLerpLastNano = now;
final float target = zoomEnabled ? zoom : 1.0F;
if (dt <= 0.0F || !(boolean) Settings.ZOOM_SMOOTH.option.getStore()) {
currentZoom = target;
return;
}
// Clamp dt so a long frame (alt-tab, GC pause) does not snap the zoom.
dt = Math.min(dt, 0.1F);
final int rate = (int) Settings.ZOOM_SMOOTH_SPEED.option.getStore();
currentZoom += (target - currentZoom) * (1.0F - (float) Math.exp(-dt * rate));
if (Math.abs(target - currentZoom) < ZOOM_SMOOTH_SNAP_EPSILON) {
currentZoom = target;
}
}
private static void resetMouseFilters(Minecraft mc) {
if (mc.entityRenderer != null) {
((IMouseFilterExt) mc.entityRenderer.mouseFilterXAxis).angelica$reset();
@@ -79,4 +111,10 @@ public class Zoom {
handleKeyEvent();
}
}
@SubscribeEvent
public void onRenderTick(TickEvent.RenderTickEvent e) {
if (e.phase != TickEvent.Phase.START) return;
updateZoomLerp();
}
}
@@ -0,0 +1,99 @@
package com.prupe.mcpatcher.ctm;
import com.prupe.mcpatcher.ctm.TileOverrideImpl.CTMCompactExpanded;
import com.prupe.mcpatcher.mal.tile.TileLoader;
import net.minecraft.util.ResourceLocation;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public class CTMTextureGenerator {
public static void generateTextures(BufferedImage[] compactIcons, CTMCompactExpanded override,
ResourceLocation propsLoc, ResourceLocation blankResource){
BufferedImage cFull = compactIcons[0]; // Full
BufferedImage cNone = compactIcons[1]; // None
BufferedImage cVert = compactIcons[2]; // Vertical
BufferedImage cHori = compactIcons[3]; // Horizontal
BufferedImage cCorn = compactIcons[4]; // Corner
BufferedImage[] expanded = new BufferedImage[47];
// Generate all 47 textures to match normal CTM
expanded[0] = cFull;
expanded[1] = generate(cFull, cHori, cFull, cHori);
expanded[2] = cHori;
expanded[3] = generate(cHori, cFull, cHori, cFull);
expanded[4] = generate(cFull, cHori, cVert, cCorn);
expanded[5] = generate(cHori, cFull, cCorn, cVert);
expanded[6] = generate(cVert, cCorn, cVert, cCorn);
expanded[7] = generate(cHori, cHori, cCorn, cCorn);
expanded[8] = generate(cCorn, cNone, cCorn, cCorn);
expanded[9] = generate(cCorn, cCorn, cCorn, cNone);
expanded[10] = generate(cNone, cCorn, cNone, cCorn);
expanded[11] = generate(cNone, cNone, cCorn, cCorn);
expanded[12] = generate(cFull, cFull, cVert, cVert);
expanded[13] = generate(cFull, cHori, cVert, cNone);
expanded[14] = generate(cHori, cHori, cNone, cNone);
expanded[15] = generate(cHori, cFull, cNone, cVert);
expanded[16] = generate(cVert, cCorn, cFull, cHori);
expanded[17] = generate(cCorn, cVert, cHori, cFull);
expanded[18] = generate(cCorn, cCorn, cHori, cHori);
expanded[19] = generate(cCorn, cVert, cCorn, cVert);
expanded[20] = generate(cNone, cCorn, cCorn, cCorn);
expanded[21] = generate(cCorn, cCorn, cNone, cCorn);
expanded[22] = generate(cCorn, cCorn, cNone, cNone);
expanded[23] = generate(cCorn, cNone, cCorn, cNone);
expanded[24] = cVert;
expanded[25] = generate(cVert, cNone, cVert, cNone);
expanded[26] = cNone;
expanded[27] = generate(cNone, cVert, cNone, cVert);
expanded[28] = generate(cVert, cCorn, cVert, cNone);
expanded[29] = generate(cHori, cHori, cNone, cCorn);
expanded[30] = generate(cVert, cNone, cVert, cCorn);
expanded[31] = generate(cHori, cHori, cCorn, cNone);
expanded[32] = generate(cNone, cNone, cNone, cCorn);
expanded[33] = generate(cNone, cNone, cCorn, cNone);
expanded[34] = generate(cCorn, cNone, cNone, cCorn);
expanded[35] = generate(cNone, cCorn, cCorn, cNone);
expanded[36] = generate(cVert, cVert, cFull, cFull);
expanded[37] = generate(cVert, cNone, cFull, cHori);
expanded[38] = generate(cNone, cNone, cHori, cHori);
expanded[39] = generate(cNone, cVert, cHori, cFull);
expanded[40] = generate(cCorn, cNone, cHori, cHori);
expanded[41] = generate(cNone, cVert, cNone, cVert);
expanded[42] = generate(cNone, cCorn, cHori, cHori);
expanded[43] = generate(cCorn, cVert, cNone, cVert);
expanded[44] = generate(cNone, cCorn, cNone, cNone);
expanded[45] = generate(cCorn, cNone, cNone, cNone);
expanded[46] = cCorn;
for (int i = 0; i < expanded.length; i++){
ResourceLocation resource =
TileLoader.parseTileAddress(propsLoc, String.valueOf(i), blankResource);
override.addIcon(resource, expanded[i]);
}
}
private static BufferedImage generate(BufferedImage tl, BufferedImage tr, BufferedImage bl, BufferedImage br){
int w = tl.getWidth();
int hw = w/2;
BufferedImage img = new BufferedImage(tl.getWidth(), tl.getHeight(), BufferedImage.TYPE_INT_ARGB);
int numFrames = tl.getHeight() / tl.getWidth();
Graphics2D g = img.createGraphics();
for (int i = 0; i < numFrames; i++){
int yOff = w * i;
copy(tl, g, 0, yOff, hw);
copy(tr, g, hw, yOff, hw);
copy(bl, g, 0, yOff + hw, hw);
copy(br, g, hw, yOff + hw, hw);
}
g.dispose();
return img;
}
private static void copy(BufferedImage src, Graphics2D g, int x, int y, int s){
g.drawImage(src, x, y, x+s, y+s, x, y, x+s, y+s, null);
}
}
@@ -10,12 +10,12 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.StampedLock;
import com.github.bsideup.jabel.Desugar;
import net.minecraft.block.Block;
import net.minecraft.util.IIcon;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess;
import com.github.bsideup.jabel.Desugar;
import com.prupe.mcpatcher.MCLogger;
import com.prupe.mcpatcher.MCPatcherUtils;
import com.prupe.mcpatcher.mal.block.BlockAPI;
@@ -32,7 +32,7 @@ import jss.notfine.config.MCPatcherForgeConfig;
public class CTMUtils {
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
public static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
private static class Overrides {
private final List<TileOverride> all = new ArrayList<>();
@@ -0,0 +1,77 @@
package com.prupe.mcpatcher.ctm;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.prupe.mcpatcher.mal.tile.TileLoader;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import jss.notfine.render.InterpolatedIcon;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.SimpleResource;
import net.minecraft.client.resources.data.AnimationMetadataSection;
import net.minecraft.util.ResourceLocation;
import java.awt.image.BufferedImage;
@SideOnly(Side.CLIENT)
public class GeneratedCTMAtlasSprite extends InterpolatedIcon {
private final TileLoader loader;
private final boolean aniFiltering;
private boolean interpolated;
public GeneratedCTMAtlasSprite(TileLoader loader, boolean aniFiltering, String name) {
super(name);
this.loader = loader;
this.aniFiltering = aniFiltering;
}
@Override
protected void updateAnimationInterpolated() throws IllegalArgumentException, IllegalAccessException {
if(interpolated) super.updateAnimationInterpolated();
}
@Override
public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) {
return true;
}
@Override
public boolean load(IResourceManager manager, ResourceLocation location) {
BufferedImage img = loader.getImageForPath(location);
if(img == null) return true;
try {
ResourceLocation metaLoc = getMetaLoc(location);
IResource iresource = manager.getResource(metaLoc);
AnimationMetadataSection anim = (AnimationMetadataSection)iresource.getMetadata("animation");
interpolated = anim != null && AngelicaConfig.enableNotFineFeatures && shouldInterpolate(iresource);
loadSprite(new BufferedImage[]{img, null, null, null, null}, anim, aniFiltering);
}catch (Exception exception){
CTMUtils.logger.error("Error loading sprite for " + location);
exception.printStackTrace();
return true;
}
return false;
}
private static boolean shouldInterpolate(IResource resource){
try {
if (resource instanceof SimpleResource simple) {
return simple.mcmetaJson.getAsJsonObject("animation")
.getAsJsonPrimitive("interpolate").getAsBoolean();
}
}catch (Exception _){}
return false;
}
/**
* Find the mcmeta file associated with 0.png
*/
private static ResourceLocation getMetaLoc(ResourceLocation location) {
String path = location.getResourcePath();
int index = path.lastIndexOf('/');
if(index == -1) return new ResourceLocation(location.getResourceDomain(), "0.png");
path = path.substring(0, index) + "/0.png";
return new ResourceLocation(location.getResourceDomain(), path);
}
}
@@ -5,6 +5,7 @@ import static com.prupe.mcpatcher.ctm.RenderBlockState.CONNECT_BY_MATERIAL;
import static com.prupe.mcpatcher.ctm.RenderBlockState.CONNECT_BY_TILE;
import static com.prupe.mcpatcher.ctm.RenderBlockState.NORMALS;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
@@ -32,10 +33,10 @@ public abstract class TileOverride implements Comparable<TileOverride> {
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
private final PropertiesFile properties;
protected final PropertiesFile properties;
private final String baseFilename;
private final TileLoader tileLoader;
private final int renderPass;
protected final TileLoader tileLoader;
protected final int renderPass;
private final int weight;
private final List<BlockStateMatcher> matchBlocks;
private final Set<String> matchTiles;
@@ -45,7 +46,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
private final BitSet biomes;
private final BitSet height;
private final List<ResourceLocation> tileNames = new ArrayList<>();
protected final List<ResourceLocation> tileNames = new ArrayList<>();
protected IIcon[] icons;
// Index into this array is formed from these bit values:
@@ -103,6 +104,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
case "sandstone", "top" -> override = new TileOverrideImpl.Top(properties, tileLoader);
case "repeat", "pattern" -> override = new TileOverrideImpl.Repeat(properties, tileLoader);
case "ctm_compact", "compact" -> override = new TileOverrideImpl.CTMCompact(properties, tileLoader);
case "compact_expanded" -> override = new TileOverrideImpl.CTMCompactExpanded(properties, tileLoader);
default -> properties.error("unknown method \"%s\"", method);
}
@@ -196,7 +198,12 @@ public abstract class TileOverride implements Comparable<TileOverride> {
return tileLoader.preloadTile(resource, renderPass > RenderPassAPI.MAX_BASE_RENDER_PASS);
}
private void loadIcons() {
public void addIcon(ResourceLocation resource, BufferedImage img){
tileNames.add(resource);
tileLoader.addTile(resource, img, null, true);
}
protected void loadIcons() {
tileNames.clear();
String tileList = properties.getString("tiles", "");
ResourceLocation blankResource = RenderPassAPI.instance.getBlankResource(renderPass);
@@ -221,16 +228,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
try {
int from = Integer.parseInt(matcher.group(1));
int to = Integer.parseInt(matcher.group(2));
for (int i = from; i <= to; i++) {
ResourceLocation resource = TileLoader
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
if (TexturePackAPI.hasResource(resource)) {
addIcon(resource);
} else {
properties.warning("could not find image %s", resource);
tileNames.add(null);
}
}
loadOverrideIcons(from, to, blankResource);
} catch (NumberFormatException e) {
e.printStackTrace();
}
@@ -250,6 +248,19 @@ public abstract class TileOverride implements Comparable<TileOverride> {
}
}
protected void loadOverrideIcons(int from, int to, ResourceLocation blankResource){
for (int i = from; i <= to; i++) {
ResourceLocation resource = TileLoader
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
if (TexturePackAPI.hasResource(resource)) {
addIcon(resource);
} else {
properties.warning("could not find image %s", resource);
tileNames.add(null);
}
}
}
private List<BlockStateMatcher> getBlockList(String property, String defaultMetadata) {
List<BlockStateMatcher> blocks = new ArrayList<>();
if (!MCPatcherUtils.isNullOrEmpty(defaultMetadata)) {
@@ -12,15 +12,22 @@ import static com.prupe.mcpatcher.ctm.RenderBlockState.REL_UL;
import static com.prupe.mcpatcher.ctm.RenderBlockState.REL_UR;
import static com.prupe.mcpatcher.ctm.RenderBlockState.TOP_FACE;
import com.prupe.mcpatcher.mal.block.RenderPassAPI;
import com.prupe.mcpatcher.mal.resource.TexturePackAPI;
import net.minecraft.util.IIcon;
import com.prupe.mcpatcher.mal.resource.PropertiesFile;
import com.prupe.mcpatcher.mal.tile.TileLoader;
import com.prupe.mcpatcher.mal.util.WeightedIndex;
import net.minecraft.util.ResourceLocation;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
public class TileOverrideImpl {
final static class CTM extends TileOverride {
static class CTM extends TileOverride {
CTM(PropertiesFile properties, TileLoader tileLoader) {
super(properties, tileLoader);
@@ -505,4 +512,48 @@ public class TileOverrideImpl {
return p;
}
}
final public static class CTMCompactExpanded extends CTM {
CTMCompactExpanded(PropertiesFile propertiesFile, TileLoader tileLoader) {
super(propertiesFile, tileLoader);
}
@Override
String checkTileMap() {
return null;
}
@Override
String getMethod() {
return "compact_expanded";
}
@Override
protected void loadOverrideIcons(int from, int to, ResourceLocation blankResource) {
List<BufferedImage> compactIcons = new ArrayList<>();
if(from != 0){
properties.error("expanded compact CTM requires range to start at 0, starts at %d", from);
}
if(to - from + 1 != 5){
properties.error("expanded compact CTM requires exactly 5 icons, got range %d - %d", from, to);
}
for (int i = from; i <= to; i++) {
ResourceLocation resource = TileLoader
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
if (TexturePackAPI.hasResource(resource)) {
compactIcons.add(tileLoader.loadResourceImage(resource,
renderPass > RenderPassAPI.MAX_BASE_RENDER_PASS));
} else {
// Promote from warning to error for compact CTM
properties.error("could not find image %s, required for expanded compact CTM", resource);
tileNames.add(null);
}
}
if(compactIcons.size() == 5){
CTMTextureGenerator.generateTextures(compactIcons.toArray(new BufferedImage[0]),
this, properties.getResource(), blankResource);
}
}
}
}
@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.prupe.mcpatcher.ctm.GeneratedCTMAtlasSprite;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
@@ -44,6 +45,7 @@ public class TileLoader {
private TextureMap baseTextureMap;
private final Map<String, TextureAtlasSprite> baseTexturesByName = new HashMap<>();
private final Set<ResourceLocation> tilesToRegister = new HashSet<>();
private final Set<ResourceLocation> generatedTiles = new HashSet<>();
private final Map<ResourceLocation, BufferedImage> tileImages = new HashMap<>();
private final Map<String, IIcon> iconMap = new HashMap<>();
@@ -119,6 +121,10 @@ public class TileLoader {
logger.fine("after registerIcons(%s) %d icons", mapName, map.size());
}
public BufferedImage getImageForPath(ResourceLocation rl) {
return tileImages.get(rl);
}
public static String getOverridePath(String prefix, String basePath, String name, String ext) {
String path;
if (name.endsWith(".png")) {
@@ -218,6 +224,22 @@ public class TileLoader {
if (tileImages.containsKey(resource)) {
return true;
}
return addTile(resource, loadResourceImage(resource, alternate), special, false);
}
public boolean addTile(ResourceLocation resource, BufferedImage image, String special, boolean generated) {
tilesToRegister.add(resource);
tileImages.put(resource, image);
if(generated){
generatedTiles.add(resource);
}
if (special != null) {
specialTextures.put(resource.toString(), special);
}
return true;
}
public BufferedImage loadResourceImage(ResourceLocation resource, boolean alternate){
BufferedImage image = null;
if (!MCPatcherForgeConfig.ConnectedTextures.debugTextures) {
image = TexturePackAPI.getImage(resource);
@@ -228,12 +250,7 @@ public class TileLoader {
if (image == null) {
image = generateDebugTexture(resource.getResourcePath(), 64, 64, alternate);
}
tilesToRegister.add(resource);
tileImages.put(resource, image);
if (special != null) {
specialTextures.put(resource.toString(), special);
}
return true;
return image;
}
public boolean preloadTile(ResourceLocation resource, boolean alternate) {
@@ -287,8 +304,14 @@ public class TileLoader {
return false;
}
}
IIcon icon = textureMap.registerIcon(name);
map.put(name, (TextureAtlasSprite) icon);
TextureAtlasSprite icon;
if(generatedTiles.contains(resource)){
icon = new GeneratedCTMAtlasSprite(this, textureMap.anisotropicFiltering > 1, name);
textureMap.setTextureEntry(name, icon);
}else{
icon = (TextureAtlasSprite)textureMap.registerIcon(name);
}
map.put(name, icon);
iconMap.put(name, icon);
String extra = (width == height ? "" : ", " + (height / width) + " frames");
subLogger.finer("%s -> %s icon %dx%d%s", name, mapName, width, width, extra);
@@ -299,6 +322,7 @@ public class TileLoader {
public void finish() {
tilesToRegister.clear();
tileImages.clear();
generatedTiles.clear();
}
public IIcon getIcon(String name) {
+3 -1
View File
@@ -174,7 +174,9 @@ public enum Settings {
RenderStars.reloadStarRenderList(Minecraft.getMinecraft().renderGlobal);
}
},
VOID_FOG(new NotFineOptionTickBox(false, OptionImpact.LOW));
VOID_FOG(new NotFineOptionTickBox(false, OptionImpact.LOW)),
ZOOM_SMOOTH(new NotFineOptionTickBox(true, OptionImpact.LOW)),
ZOOM_SMOOTH_SPEED(new NotFineOptionSlider(14, 1, 30, 1, OptionImpact.LOW));
public final NotFineOption<?> option;
@@ -1,6 +1,7 @@
package jss.notfine.gui;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import jss.notfine.config.NotFineConfig;
import jss.notfine.core.Settings;
@@ -169,6 +170,12 @@ public class NotFineGameOptionPages {
.build());
}
if (AngelicaConfig.enableZoom) {
groups.add(OptionGroup.createBuilder()
.add(Settings.ZOOM_SMOOTH.option)
.add(Settings.ZOOM_SMOOTH_SPEED.option)
.build());
}
return new OptionPage(I18n.format("options.video"), ImmutableList.copyOf(groups));
}
@@ -29,7 +29,7 @@ public class InterpolatedIcon extends TextureAtlasSprite {
}
}
private void updateAnimationInterpolated() throws IllegalArgumentException, IllegalAccessException {
protected void updateAnimationInterpolated() throws IllegalArgumentException, IllegalAccessException {
double d0 = 1.0D - tickCounter / (double) animationMetadata.getFrameTimeSingle(frameCounter);
int i = animationMetadata.getFrameIndex(frameCounter);
@@ -532,6 +532,13 @@ public class SodiumGameOptionPages {
.build())
.build());
if (AngelicaConfig.enableZoom) {
groups.add(OptionGroup.createBuilder()
.add(Settings.ZOOM_SMOOTH.option)
.add(Settings.ZOOM_SMOOTH_SPEED.option)
.build());
}
return new OptionPage(I18n.format("sodium.options.pages.appearance"), ImmutableList.copyOf(groups));
}
+8 -4
View File
@@ -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) {
@@ -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 -> {
@@ -55,7 +55,7 @@ public class PackRenderTargetDirectives {
renderTargetSettings.forEach((index, settings) -> {
if (settings.shouldClear()) {
buffersToBeCleared.add(index.intValue());
buffersToBeCleared.add(index);
}
});
@@ -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) {
@@ -78,3 +78,7 @@ options.void_fog=Void Fog
options.void_fog.tooltip=Void Fog
options.hurt_shake=Hurt Screen Shake
options.background.random=Random
options.zoom_smooth=Smooth Zoom
options.zoom_smooth.tooltip=Smoothly interpolates the camera toward the zoom level instead of snapping instantly.
options.zoom_smooth_speed=Smooth Zoom Speed
options.zoom_smooth_speed.tooltip=How fast smooth zoom converges to the target zoom. Higher is snappier, lower is floatier. No effect when Smooth Zoom is off.
@@ -1,5 +1,7 @@
package com.gtnewhorizons.angelica.mixins.early.angelica;
import com.gtnewhorizons.angelica.event.ClientEvent;
import com.gtnewhorizons.angelica.event.ClientEventType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.shader.Framebuffer;
@@ -15,6 +17,7 @@ public class MixinMinecraft_IconifyGuard {
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;updateCameraAndRender(F)V")
)
private void angelica$skipRenderWhenIconified(EntityRenderer entityRenderer, float partialTicks) {
ClientEvent.post(ClientEventType.ON_TICK);
final Framebuffer fb = Minecraft.getMinecraft().getFramebuffer();
if (fb == null || fb.framebufferWidth < 16 || fb.framebufferHeight < 16) {
return;
@@ -13,7 +13,6 @@ import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -23,6 +22,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Single-pass damage-overlay tint, modeled on modern Minecraft's OverlayTexture.
* The tint is applied only while the main body model renders.
*/
@Mixin(RendererLivingEntity.class)
public class MixinRendererLivingEntity_OverlayTint {
@@ -33,8 +33,6 @@ public class MixinRendererLivingEntity_OverlayTint {
@Unique private boolean angelica$ffpOverlayActive;
@Unique private boolean angelica$shaderEntityColorActive;
@Unique private boolean angelica$emissivePass;
@Inject(
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
at = @At(value = "INVOKE",
@@ -64,20 +62,13 @@ public class MixinRendererLivingEntity_OverlayTint {
@Inject(
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V"),
target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderModel(Lnet/minecraft/entity/EntityLivingBase;FFFFFF)V",
shift = At.Shift.AFTER),
require = 1, expect = 1
)
private void angelica$teardownOverlay(EntityLivingBase entity, double x, double y, double z,
float yaw, float partialTick, CallbackInfo ci) {
if (angelica$ffpOverlayActive) {
GLStateManager.setOverlayColor(0.0F, 0.0F, 0.0F, 0.0F);
angelica$ffpOverlayActive = false;
}
if (angelica$shaderEntityColorActive) {
// Don't tint held items
CapturedRenderingState.INSTANCE.setCurrentEntityColor(0.0F, 0.0F, 0.0F, 0.0F);
angelica$shaderEntityColorActive = false;
}
private void angelica$clearBodyTint(EntityLivingBase entity, double x, double y, double z,
float yaw, float partialTick, CallbackInfo ci) {
angelica$clearOverlayColor();
}
/**
@@ -100,64 +91,17 @@ public class MixinRendererLivingEntity_OverlayTint {
original.call(model, entity, p1, p2, p3, p4, p5, p6);
}
/**
* Prevent bleed by saving last state and comparing with current blend state.
*/
@WrapOperation(
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;shouldRenderPass(Lnet/minecraft/entity/EntityLivingBase;IF)I"),
require = 1, expect = 1
)
private int angelica$detectEmissivePass(RendererLivingEntity self, EntityLivingBase entity, int pass,
float partialTick, Operation<Integer> original) {
GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
final int result = original.call(self, entity, pass, partialTick);
final int srcAfter = GLStateManager.glGetInteger(GL14.GL_BLEND_SRC_RGB);
final int dstAfter = GLStateManager.glGetInteger(GL14.GL_BLEND_DST_RGB);
angelica$emissivePass = srcAfter == GL11.GL_ONE && dstAfter == GL11.GL_ONE;
return result;
}
/**
* Skip the overlay on emissive eye pass.
*/
@WrapOperation(
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/model/ModelBase;render(Lnet/minecraft/entity/Entity;FFFFFF)V"),
slice = @Slice(
from = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;shouldRenderPass(Lnet/minecraft/entity/EntityLivingBase;IF)I"),
to = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V")
),
require = 1, expect = 1
)
private void angelica$untintEmissivePass(ModelBase model, Entity entity,
float p1, float p2, float p3, float p4, float p5, float p6, Operation<Void> original) {
if (!angelica$skipReRender || !angelica$emissivePass) {
original.call(model, entity, p1, p2, p3, p4, p5, p6);
return;
}
if (angelica$ffpOverlayActive) {
GLStateManager.setOverlayColor(0.0F, 0.0F, 0.0F, 0.0F);
original.call(model, entity, p1, p2, p3, p4, p5, p6);
GLStateManager.setOverlayColor(1.0F, 0.0F, 0.0F, ANGELICA$RED_MIX);
} else if (angelica$shaderEntityColorActive) {
CapturedRenderingState.INSTANCE.setCurrentEntityColor(0.0F, 0.0F, 0.0F, 0.0F);
original.call(model, entity, p1, p2, p3, p4, p5, p6);
CapturedRenderingState.INSTANCE.setCurrentEntityColor(1.0F, 0.0F, 0.0F, ANGELICA$RED_MIX);
} else {
original.call(model, entity, p1, p2, p3, p4, p5, p6);
}
}
@Inject(
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
at = @At("RETURN")
)
private void angelica$reset(CallbackInfo ci) {
angelica$clearOverlayColor();
angelica$skipReRender = false;
}
@Unique
private void angelica$clearOverlayColor() {
if (angelica$ffpOverlayActive) {
GLStateManager.setOverlayColor(0.0F, 0.0F, 0.0F, 0.0F);
angelica$ffpOverlayActive = false;
@@ -166,8 +110,6 @@ public class MixinRendererLivingEntity_OverlayTint {
CapturedRenderingState.INSTANCE.setCurrentEntityColor(0.0F, 0.0F, 0.0F, 0.0F);
angelica$shaderEntityColorActive = false;
}
angelica$skipReRender = false;
angelica$emissivePass = false;
}
@Unique
@@ -16,10 +16,8 @@ public class MixinEntityRenderer_Zoom {
@ModifyReturnValue(method = "getFOVModifier", at = @At("RETURN"))
private float angelica$modifyFOV(float original) {
if (Zoom.getZoomKey().getIsKeyPressed()) {
return original / Zoom.getZoom();
}
return original;
final float current = Zoom.getCurrentZoom();
return current > 1.0001F ? original / current : original;
}
@ModifyConstant(method = "updateCameraAndRender", constant = @Constant(floatValue = 8.0F))
@@ -169,7 +169,7 @@ public abstract class MixinRenderBlocks {
}
@ModifyExpressionValue(method = { "renderStandardBlockWithColorMultiplier" },
at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/renderer/RenderBlocks;renderAllFaces:Z"))
at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/renderer/RenderBlocks;renderAllFaces:Z"))
private boolean applyAOBrightness(boolean original, @Local(ordinal = 0) Tessellator tessellator) {
((StateAwareTessellator)tessellator).angelica$setAppliedAo(this.applyingCeleritasAO);
return original;
@@ -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();
}
}
@@ -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();
}
}
@@ -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();
}
}