Compare commits

..
30 Commits
Author SHA1 Message Date
Eclipse-Sol 3ebc8868c7 Fix item reset hopefully for the last time (#1621) 2026-03-30 19:32:47 -07:00
JohnButlerThird 0938e6d975 Only run the logic on bop grass (fix my mod bugging out) (#1620) 2026-03-30 18:17:42 -07:00
Eclipse-Sol d3022a40d2 Create new deferred overlay system to fix z-fighting issues (#1605) 2026-03-30 15:50:18 -07:00
Eclipse-Sol 2645c803f9 Better horse support (#1599) 2026-03-30 15:41:53 -07:00
Jason Mitchell d91c356a99 Shader fixes (#1619) 2026-03-30 15:34:54 -07:00
Jason Mitchell 189ff4a80f Defer client attributes. They're uploaded/handled elsewhere. Should fix a crash on j8/lwjgl2 (#1618) 2026-03-30 09:58:40 -07:00
Jason Mitchell ffb4ca9472 Get rid of some allocations, and use immutable variants for the suppliers (#1612) 2026-03-30 09:58:27 -07:00
Jason Mitchell 7d8c8d306d More Double overloads (#1613) 2026-03-29 15:09:13 -07:00
Kotmatross 117ff0cacf Fix other dynamic uniforms not updating properly (#1610) 2026-03-29 12:53:09 -07:00
Jason Mitchell 83fdd57534 Narrow another overly broad transformer exclusion 2026-03-29 09:24:50 -07:00
Kaiz 951be04e9a fix: correctly handle cross-chunk TileEntity render bounds 2026-03-29 09:20:13 -07:00
Jason Mitchell 0ad69f3433 FINE, we'll work with java8/forge. 2026-03-28 20:09:42 -07:00
Fabian Maurer 0dabecc784 Handle GL_POLYGON in legacy conversion 2026-03-28 14:41:23 -07:00
Jason Mitchell 9b3fad4c6d Ensure sufficient coverage + optimize the check 2026-03-28 13:16:54 -07:00
Kaiz e1e8256861 fix: crash when client-side vertex attrib pointers are used in core profile 2026-03-28 13:16:54 -07:00
Jason Mitchell e65c01c2a3 Handle method handles in invokedynamic 2026-03-28 12:46:19 -07:00
Jason Mitchell b9de4df18e Update alpha test to hopefully work with RTM and AE2 (#1597) 2026-03-28 09:40:10 -07:00
Kotmatross a5d31cd1b6 Return phaseChangeNotifier (#1596) 2026-03-28 09:15:46 -07:00
DarkShadow44 29f8d718cc Pass texturemap to composite shader and honor texture replacements (#1589) 2026-03-27 19:07:45 -07:00
12411234 52b0db2566 Fix missing glGetTexImage method crash when using XaerosWorldMap (#1592) 2026-03-27 19:02:51 -07:00
Eclipse-Sol e9eb45f4f2 Centers the Wither Armor (#1590) 2026-03-27 18:37:17 -07:00
Jason Mitchell 92e28a4cd5 Blur Compat (#1593) 2026-03-27 18:32:24 -07:00
Jason Mitchell f46a86889c Fix crash with fancy block particles. (#1591) 2026-03-27 17:52:14 -07:00
Jason MitchellandAlexdoru c827d446d5 External Redirector API (#1580)
Co-authored-by: Alexdoru <[email protected]>
2026-03-27 11:20:29 -07:00
Eclipse-Sol 00ef355ce8 Fix sky lighting on drawCrossSquare rendered blocks. (#1576) 2026-03-25 18:58:40 -07:00
Kotmatross 1282056fff Fix blend leak in BatchingFontRenderer (#1575) 2026-03-25 15:34:43 -07:00
Alexdoru 6c422d47a2 Make the mod no-op on server (#1574) 2026-03-25 12:59:23 -07:00
DarkShadow44 057ea8035c Distant Horizons shader support (#1553) 2026-03-25 10:48:14 -07:00
Jason Mitchell 3ea47c8385 Various fixes (#1571) 2026-03-24 22:17:40 -07:00
Eclipse-Sol 306d732d81 Fixes 3rd person enchant glints z-fighting with the item model (#1569) 2026-03-24 17:24:23 -07:00
141 changed files with 4695 additions and 767 deletions

No files matched your search

+5 -2
View File
@@ -83,7 +83,7 @@ dependencies {
shadowImplementation("net.minecraftforge:eventbus:7.0-beta.15")
shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-26.g5ee7d96-GTNH") {
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-32.g7dd88a4-GTNH") {
exclude module: "antlr4" // we only want to shadow the runtime module
}
shadowImplementation("org.antlr:antlr4-runtime:4.13.2")
@@ -119,7 +119,7 @@ dependencies {
compileOnly("com.github.GTNewHorizons:NotEnoughIds:2.1.10:dev")
compileOnly(rfg.deobf("maven.modrinth:ntmspace:X5593_H261"))
compileOnly(rfg.deobf("maven.modrinth:ntmspace:X5634_H261"))
compileOnly(rfg.deobf("curse.maven:campfirebackport-387444:4611675"))
compileOnly(rfg.deobf("curse.maven:xaeros-minimap-263420:5060684"))
@@ -136,6 +136,9 @@ dependencies {
// Better Crashes
compileOnly("com.github.GTNewHorizons:BetterCrashes:1.4.1-GTNH:dev")
// Distant Horizons
compileOnly("maven.modrinth:DistantHorizonsApi:5.1.0")
afterEvaluate {
dependencies {
testImplementation(platform('org.junit:junit-bom:5.14.1'))
+2 -1
View File
@@ -76,7 +76,7 @@ dependencies {
compileOnly("org.lwjgl.lwjgl:lwjgl:${property("lwjglVersion")}")
compileOnly("org.lwjgl.lwjgl:lwjgl_util:${property("lwjglVersion")}")
compileOnly("org.ow2.asm:asm-tree:9.7")
compileOnly("org.ow2.asm:asm-tree:5.0.3")
// Our Deps
api("com.github.GTNewHorizons:GTNHLib:${property("gtnhlibVersion")}:dev")
@@ -100,6 +100,7 @@ dependencies {
testImplementation(sourceSets["stubs"].output)
testImplementation(platform("org.junit:junit-bom:${property("junitBomVersion")}"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.ow2.asm:asm-tree:9.7")
testImplementation("org.lwjgl.lwjgl:lwjgl:${property("lwjglVersion")}")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testRuntimeOnly("org.apache.logging.log4j:log4j-core:${property("log4jVersion")}")
@@ -345,6 +345,16 @@ public class FeedbackManager {
}
break;
case GL11.GL_POLYGON:
if (count >= 3) {
feedbackToken(GL11.GL_POLYGON_TOKEN);
feedbackToken(count);
for (int i = 0; i < count; i++) {
emitVertex(reader.read(i), stride);
}
}
break;
default:
throw new UnsupportedOperationException("Feedback mode: unsupported primitive mode 0x" + Integer.toHexString(mode));
}
@@ -419,6 +419,9 @@ public class GLStateManager {
@Getter protected static int boundVBO;
@Getter protected static int boundEBO;
@Getter protected static int boundVAO;
private static int clientArraysVBO = 0;
private static int clientArraysVBOCapacity = 0;
private static final int[] clientArraysVBOOffsets = new int[VertexAttribState.MAX_ATTRIBS];
private static int boundPixelUnpackBuffer;
private static int boundPixelPackBuffer;
private static final Int2IntOpenHashMap vaoEboMap = new Int2IntOpenHashMap();
@@ -2145,6 +2148,7 @@ public class GLStateManager {
}
prepareWideLineEmulation(mode);
ShaderManager.getInstance().preDraw();
prepareClientArrays();
RENDER_BACKEND.drawElements(mode, indices);
}
@@ -2158,6 +2162,7 @@ public class GLStateManager {
}
prepareWideLineEmulation(mode);
ShaderManager.getInstance().preDraw();
prepareClientArrays();
if (mode == GL11.GL_QUADS) {
QuadConverter.drawQuadElementsAsTriangles(indices);
} else {
@@ -2175,6 +2180,7 @@ public class GLStateManager {
}
prepareWideLineEmulation(mode);
ShaderManager.getInstance().preDraw();
prepareClientArrays();
if (mode == GL11.GL_QUADS) {
QuadConverter.drawQuadElementsAsTriangles(indices);
} else {
@@ -2192,6 +2198,7 @@ public class GLStateManager {
}
prepareWideLineEmulation(mode);
ShaderManager.getInstance().preDraw();
prepareClientArrays();
if (mode == GL11.GL_QUADS) {
QuadConverter.drawQuadElementsAsTriangles(count, type, indices);
} else {
@@ -2223,6 +2230,7 @@ public class GLStateManager {
}
prepareWideLineEmulation(mode);
ShaderManager.getInstance().preDraw();
prepareClientArrays();
if (mode == GL11.GL_QUADS) {
QuadConverter.drawQuadElementsAsTriangles(indices_count, type, indices_buffer_offset);
} else {
@@ -2245,20 +2253,72 @@ public class GLStateManager {
public static void glMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
ShaderManager.getInstance().preDraw();
prepareClientArrays();
RENDER_BACKEND.multiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
}
public static void glMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
ShaderManager.getInstance().preDraw();
prepareClientArrays();
RENDER_BACKEND.multiDrawElementsBaseVertex(mode, pCount, type, pIndices, drawcount, pBaseVertex);
}
public static void glDrawElementsBaseVertex(int mode, int count, int type, long indices, int basevertex) {
ShaderManager.getInstance().preDraw();
prepareClientArrays();
RENDER_BACKEND.drawElementsBaseVertex(mode, count, type, indices, basevertex);
}
public static void glDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) { RENDER_BACKEND.drawElementsInstanced(mode, count, type, indices, primcount); }
public static void glDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
ShaderManager.getInstance().preDraw();
prepareClientArrays();
RENDER_BACKEND.drawElementsInstanced(mode, count, type, indices, primcount);
}
private static void prepareClientArrays() {
if (ShaderManager.getInstance().isEnabled() && VertexAttribState.hasAnyClientSideEnabledAttrib()) {
uploadClientArraysToVBO();
}
}
/**
* If any enabled vertex attribute uses a client-side pointer (no VBO), upload all such
* attribs into a shared stream VBO so the draw succeeds under core profile.
*/
private static void uploadClientArraysToVBO() {
int totalBytes = 0;
for (int i = 0; i < VertexAttribState.MAX_ATTRIBS; i++) {
clientArraysVBOOffsets[i] = -1;
final VertexAttribState.Attrib a = VertexAttribState.get(i);
if (!a.enabled || a.clientPointer == null) continue;
clientArraysVBOOffsets[i] = totalBytes;
totalBytes += a.clientPointer.remaining();
}
if (totalBytes == 0) return;
if (clientArraysVBO == 0) {
clientArraysVBO = RENDER_BACKEND.genBuffers();
}
final int savedVBO = boundVBO;
glBindBuffer(GL15.GL_ARRAY_BUFFER, clientArraysVBO);
if (totalBytes > clientArraysVBOCapacity) {
int newCap = Math.max(4096, clientArraysVBOCapacity);
while (newCap < totalBytes) newCap *= 2;
clientArraysVBOCapacity = newCap;
}
RENDER_BACKEND.bufferData(GL15.GL_ARRAY_BUFFER, clientArraysVBOCapacity, GL15.GL_STREAM_DRAW);
for (int i = 0; i < VertexAttribState.MAX_ATTRIBS; i++) {
if (clientArraysVBOOffsets[i] < 0) continue;
final VertexAttribState.Attrib a = VertexAttribState.get(i);
RENDER_BACKEND.bufferSubData(GL15.GL_ARRAY_BUFFER, clientArraysVBOOffsets[i], a.clientPointer.duplicate());
RENDER_BACKEND.vertexAttribPointer(i, a.size, a.type, a.normalized, a.stride, (long) clientArraysVBOOffsets[i]);
}
glBindBuffer(GL15.GL_ARRAY_BUFFER, savedVBO);
}
public static void glDrawArrays(int mode, int first, int count) {
CommandRecorder savedRecorder = null;
@@ -2278,8 +2338,11 @@ public class GLStateManager {
}
prepareWideLineEmulation(mode);
ShaderManager.getInstance().preDraw();
prepareClientArrays();
if (mode == GL11.GL_QUADS) {
QuadConverter.drawQuadsAsTriangles(first, count);
} else if (mode == GL11.GL_POLYGON) {
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_FAN, first, count);
} else {
RENDER_BACKEND.drawArrays(mode, first, count);
}
@@ -2298,6 +2361,10 @@ public class GLStateManager {
glVertexAttribPointer(Usage.POSITION.getAttributeLocation(), size, GL11.GL_FLOAT, false, stride, MemoryUtilities.memByteBuffer(pointer));
}
public static void glVertexPointer(int size, int stride, DoubleBuffer pointer) {
glVertexAttribPointer(Usage.POSITION.getAttributeLocation(), size, GL11.GL_DOUBLE, false, stride, MemoryUtilities.memByteBuffer(pointer));
}
public static void glVertexPointer(int size, int type, int stride, ByteBuffer pointer) {
glVertexAttribPointer(Usage.POSITION.getAttributeLocation(), size, type, false, stride, pointer);
}
@@ -2339,6 +2406,10 @@ public class GLStateManager {
glNormalPointer(GL11.GL_INT, stride, pointer);
}
public static void glNormalPointer(int stride, DoubleBuffer pointer) {
glNormalPointer(GL11.GL_DOUBLE, stride, pointer);
}
public static void glNormalPointer(int type, int stride, ByteBuffer pointer) {
glVertexAttribPointer(Usage.NORMAL.getAttributeLocation(), 3, type, Usage.NORMAL.isNormalized(), stride, pointer);
}
@@ -2355,6 +2426,10 @@ public class GLStateManager {
glVertexAttribPointer(Usage.NORMAL.getAttributeLocation(), 3, GL11.GL_INT, Usage.NORMAL.isNormalized(), stride, MemoryUtilities.memByteBuffer(pointer));
}
public static void glNormalPointer(int type, int stride, DoubleBuffer pointer) {
glVertexAttribPointer(Usage.NORMAL.getAttributeLocation(), 3, GL11.GL_DOUBLE, Usage.NORMAL.isNormalized(), stride, MemoryUtilities.memByteBuffer(pointer));
}
public static void glNormalPointer(int type, int stride, long pointer_buffer_offset) {
glVertexAttribPointer(Usage.NORMAL.getAttributeLocation(), 3, type, Usage.NORMAL.isNormalized(), stride, pointer_buffer_offset);
}
@@ -2377,6 +2452,10 @@ public class GLStateManager {
glTexCoordPointer(size, GL11.GL_SHORT, stride, pointer);
}
public static void glTexCoordPointer(int size, int stride, DoubleBuffer pointer) {
glTexCoordPointer(size, GL11.GL_DOUBLE, stride, pointer);
}
public static void glTexCoordPointer(int size, int type, int stride, FloatBuffer pointer) {
final int loc = texCoordAttributeLocation();
if (loc < 0) return;
@@ -2395,6 +2474,12 @@ public class GLStateManager {
glVertexAttribPointer(loc, size, GL11.GL_INT, false, stride, MemoryUtilities.memByteBuffer(pointer));
}
public static void glTexCoordPointer(int size, int type, int stride, DoubleBuffer pointer) {
final int loc = texCoordAttributeLocation();
if (loc < 0) return;
glVertexAttribPointer(loc, size, GL11.GL_DOUBLE, false, stride, MemoryUtilities.memByteBuffer(pointer));
}
public static void glTexCoordPointer(int size, int type, int stride, long pointer_buffer_offset) {
final int loc = texCoordAttributeLocation();
if (loc < 0) return;
@@ -2441,32 +2526,23 @@ public class GLStateManager {
}
public static void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, FloatBuffer pointer) {
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
VertexAttribState.set(index, size, type, normalized, stride, bb, boundVBO);
RENDER_BACKEND.vertexAttribPointer(index, size, type, normalized, stride, bb);
VertexAttribState.set(index, size, type, normalized, stride, MemoryUtilities.memByteBuffer(pointer), 0);
}
public static void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, DoubleBuffer pointer) {
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
VertexAttribState.set(index, size, type, normalized, stride, bb, boundVBO);
RENDER_BACKEND.vertexAttribPointer(index, size, type, normalized, stride, bb);
VertexAttribState.set(index, size, type, normalized, stride, MemoryUtilities.memByteBuffer(pointer), 0);
}
public static void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, IntBuffer pointer) {
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
VertexAttribState.set(index, size, type, normalized, stride, bb, boundVBO);
RENDER_BACKEND.vertexAttribPointer(index, size, type, normalized, stride, bb);
VertexAttribState.set(index, size, type, normalized, stride, MemoryUtilities.memByteBuffer(pointer), 0);
}
public static void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, ShortBuffer pointer) {
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
VertexAttribState.set(index, size, type, normalized, stride, bb, boundVBO);
RENDER_BACKEND.vertexAttribPointer(index, size, type, normalized, stride, bb);
VertexAttribState.set(index, size, type, normalized, stride, MemoryUtilities.memByteBuffer(pointer), 0);
}
public static void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, ByteBuffer pointer) {
VertexAttribState.set(index, size, type, normalized, stride, pointer, boundVBO);
RENDER_BACKEND.vertexAttribPointer(index, size, type, normalized, stride, pointer);
VertexAttribState.set(index, size, type, normalized, stride, pointer, 0);
}
public static void glVertexAttribIPointer(int index, int size, int type, int stride, long offset) {
@@ -2475,20 +2551,15 @@ public class GLStateManager {
}
public static void glVertexAttribIPointer(int index, int size, int type, int stride, ByteBuffer pointer) {
VertexAttribState.set(index, size, type, false, stride, pointer, boundVBO);
RENDER_BACKEND.vertexAttribIPointer(index, size, type, stride, pointer);
VertexAttribState.set(index, size, type, false, stride, pointer, 0);
}
public static void glVertexAttribIPointer(int index, int size, int type, int stride, IntBuffer pointer) {
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
VertexAttribState.set(index, size, type, false, stride, bb, boundVBO);
RENDER_BACKEND.vertexAttribIPointer(index, size, type, stride, bb);
VertexAttribState.set(index, size, type, false, stride, MemoryUtilities.memByteBuffer(pointer), 0);
}
public static void glVertexAttribIPointer(int index, int size, int type, int stride, ShortBuffer pointer) {
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
VertexAttribState.set(index, size, type, false, stride, bb, boundVBO);
RENDER_BACKEND.vertexAttribIPointer(index, size, type, stride, bb);
VertexAttribState.set(index, size, type, false, stride, MemoryUtilities.memByteBuffer(pointer), 0);
}
public static void glVertexAttribDivisor(int index, int divisor) { RENDER_BACKEND.vertexAttribDivisor(index, divisor); }
@@ -5814,5 +5885,7 @@ public class GLStateManager {
public static void glGetUniform(int program, int location, IntBuffer params) {
RENDER_BACKEND.getUniformiv(program, location, params);
}
public static void glGetTexImage(int target, int level, int format, int type, long pixels) {
GL11.glGetTexImage(target, level, format, type, pixels);
}
}
@@ -36,8 +36,11 @@ public class GlslTransformUtils {
/** Reserved words added in later GLSL versions that may appear as identifiers in older shaders. */
private record ReservedWordRename(Pattern pattern, String replacement) {}
private static final Map<Integer, List<ReservedWordRename>> VERSIONED_RESERVED_WORDS = Map.of(
// Always rename sample, glsl-transformation-lib doesn't like it
0, List.of(
new ReservedWordRename(Pattern.compile("\\bsample\\b"), RENAMED_PREFIX + "sample")
),
400, List.of(
new ReservedWordRename(Pattern.compile("\\bsample\\b"), RENAMED_PREFIX + "sample"),
new ReservedWordRename(Pattern.compile("\\bsampler\\b(?!\\d)"), RENAMED_PREFIX + "sampler")
)
);
@@ -273,21 +273,27 @@ public final class FragmentShaderGenerator {
sb.append(" // Alpha test\n");
final int func = FragmentKey.decodeAlphaFunc(key.alphaTestFunc());
sb.append(" float qa = round(color.a * 255.0);\n");
switch (func) {
case GL11.GL_NEVER ->
sb.append(" discard;\n");
case GL11.GL_LESS ->
sb.append(" if (color.a >= u_AlphaRef) discard;\n");
case GL11.GL_EQUAL ->
sb.append(" if (color.a != u_AlphaRef) discard;\n");
sb.append(" if (qa >= u_AlphaRef * 255.0) discard;\n");
case GL11.GL_EQUAL -> {
sb.append(" float qr = round(u_AlphaRef * 255.0);\n");
sb.append(" if (qa != qr) discard;\n");
}
case GL11.GL_LEQUAL ->
sb.append(" if (color.a > u_AlphaRef) discard;\n");
sb.append(" if (qa > u_AlphaRef * 255.0) discard;\n");
case GL11.GL_GREATER ->
sb.append(" if (color.a <= u_AlphaRef) discard;\n");
case GL11.GL_NOTEQUAL ->
sb.append(" if (color.a == u_AlphaRef) discard;\n");
sb.append(" if (qa <= u_AlphaRef * 255.0) discard;\n");
case GL11.GL_NOTEQUAL -> {
sb.append(" float qr = round(u_AlphaRef * 255.0);\n");
sb.append(" if (qa == qr) discard;\n");
}
case GL11.GL_GEQUAL ->
sb.append(" if (color.a < u_AlphaRef) discard;\n");
sb.append(" if (qa < u_AlphaRef * 255.0) discard;\n");
case GL11.GL_ALWAYS -> {}
}
}
@@ -75,6 +75,9 @@ public final class DisplayListVBOBuilder {
if (data.drawMode == GL11.GL_QUADS) {
final IVertexArrayObject indexedVAO = new IndexedVAO(vbo, IndexBuffer.convertQuadsToTrigs(start, start + vertexCount));
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(indexedVAO, GL11.GL_TRIANGLES, 0, vertexCount / 4 * 6);
} else if (data.drawMode == GL11.GL_POLYGON) {
// GL_POLYGON is removed in core profile; convert to GL_TRIANGLE_FAN which is equivalent for convex polygons
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(vao, GL11.GL_TRIANGLE_FAN, start, vertexCount);
} else {
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(vao, data.drawMode, start, vertexCount);
}
@@ -4,16 +4,19 @@ import com.google.common.collect.ImmutableSet;
import com.gtnewhorizon.gtnhlib.asm.ClassConstantPoolParser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -79,6 +82,9 @@ public class GLSMRedirector {
glCapRedirects.put(org.lwjgl.opengl.GL11.GL_SCISSOR_TEST, "ScissorTest");
final var gl11 = RedirectMap.newMap()
// glEnable/Disable - Special cased in GLSMRedirector, but included here for the external API
.add("glEnable")
.add("glDisable")
.add("glAlphaFunc")
.add("glBegin")
.add("glBindTexture")
@@ -495,6 +501,22 @@ public class GLSMRedirector {
return CORE_EXCLUSIONS.clone();
}
/** The internal-name prefix used to match GL version classes (e.g., {@code "org/lwjgl/opengl/GL"}). */
public static String getGLPrefix() { return GL_PREFIX; }
/** The internal name of the redirect target class. */
public static String getTargetClassName() { return GLStateManager; }
/** Method redirects for GL-prefix classes. Key: original method name, Value: GLStateManager method name. */
public static Map<String, String> getGLPrefixMethodRedirects() {
return Collections.unmodifiableMap(glMethodRedirects);
}
/** Method redirects for named (non-GL-prefix) classes. Key: internal class name, Value: per-method redirect map. */
public static Map<String, Map<String, String>> getNamedClassMethodRedirects() {
return Collections.unmodifiableMap(methodRedirects);
}
public boolean shouldTransform(byte[] basicClass) {
return cstPoolParser.find(basicClass, true);
}
@@ -504,7 +526,7 @@ public class GLSMRedirector {
boolean changed = false;
final boolean isOpenGlHelper = transformedName.equals("net.minecraft.client.renderer.OpenGlHelper");
for (MethodNode mn : cn.methods) {
for (MethodNode mn : (List<MethodNode>) cn.methods) {
if (isOpenGlHelper && (mn.name.equals("glBlendFunc") || mn.name.equals("func_148821_a"))) {
continue;
}
@@ -590,6 +612,22 @@ public class GLSMRedirector {
changed = true;
}
}
} else if (node instanceof InvokeDynamicInsnNode dynNode) {
// Redirect method handles in invokedynamic bootstrap arguments
for (int i = 0; i < dynNode.bsmArgs.length; i++) {
if (!(dynNode.bsmArgs[i] instanceof Handle handle)) continue;
final Map<String, String> redirects = handle.getOwner().startsWith(GL_PREFIX) ? glMethodRedirects : methodRedirects.get(handle.getOwner());
if (redirects == null) continue;
final String glsmName = redirects.get(handle.getName());
if (glsmName == null) continue;
if (LOG_SPAM) {
final String shortOwner = handle.getOwner().substring(handle.getOwner().lastIndexOf("/") + 1);
LOGGER.info("Redirecting invokedynamic handle in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, handle.getName(), handle.getDesc(), glsmName, handle.getDesc());
}
dynNode.bsmArgs[i] = new Handle(handle.getTag(), GLStateManager, glsmName, handle.getDesc());
changed = true;
redirectInMethod = true;
}
}
}
if (ASSERT_MAIN_THREAD && redirectInMethod && !transformedName.startsWith(SplashProgress) && !(transformedName.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) {
@@ -16,16 +16,19 @@ public class VertexAttribState {
private static final Int2ObjectOpenHashMap<Attrib[]> vaoAttribs = new Int2ObjectOpenHashMap<>();
private static Attrib[] current;
private static final ArrayDeque<Attrib[]> pool = new ArrayDeque<>();
private static int clientSideEnabledCount;
public static void init(int defaultVAO) {
vaoAttribs.clear();
pool.clear();
current = allocAttribArray();
vaoAttribs.put(defaultVAO, current);
clientSideEnabledCount = 0;
}
public static void onBindVertexArray(int newVAO) {
current = vaoAttribs.computeIfAbsent(newVAO, k -> allocAttribArray());
recomputeClientSideCount();
}
public static void onDeleteVertexArray(int vaoId) {
@@ -39,6 +42,7 @@ public class VertexAttribState {
vaoAttribs.clear();
pool.clear();
current = null;
clientSideEnabledCount = 0;
}
private static Attrib[] allocAttribArray() {
@@ -55,6 +59,7 @@ public class VertexAttribState {
public static void set(int index, int size, int type, boolean normalized, int stride, long offset, int vboId) {
if (index < 0 || index >= MAX_ATTRIBS) return;
final Attrib a = current[index];
final boolean was = a.isClientSide();
a.size = size;
a.type = type;
a.normalized = normalized;
@@ -62,11 +67,13 @@ public class VertexAttribState {
a.offset = offset;
a.vboId = vboId;
a.clientPointer = null;
if (was) clientSideEnabledCount--;
}
public static void set(int index, int size, int type, boolean normalized, int stride, ByteBuffer pointer, int vboId) {
if (index < 0 || index >= MAX_ATTRIBS) return;
final Attrib a = current[index];
final boolean was = a.isClientSide();
a.size = size;
a.type = type;
a.normalized = normalized;
@@ -74,17 +81,33 @@ public class VertexAttribState {
a.offset = 0;
a.vboId = vboId;
a.clientPointer = (vboId == 0) ? pointer : null;
final boolean now = a.isClientSide();
if (was != now) clientSideEnabledCount += now ? 1 : -1;
}
public static void setEnabled(int index, boolean enabled) {
if (index < 0 || index >= MAX_ATTRIBS) return;
current[index].enabled = enabled;
final Attrib a = current[index];
if (a.clientPointer != null && a.enabled != enabled) {
clientSideEnabledCount += enabled ? 1 : -1;
}
a.enabled = enabled;
}
public static Attrib get(int index) {
return current[index];
}
private static void recomputeClientSideCount() {
int count = 0;
for (int i = 0; i < MAX_ATTRIBS; i++) {
if (current[i].isClientSide()) count++;
}
clientSideEnabledCount = count;
}
public static boolean hasVBOBoundAttrib() {
for (int i = 0; i < MAX_ATTRIBS; i++) {
if (current[i].enabled && current[i].vboId != 0) return true;
@@ -92,6 +115,14 @@ public class VertexAttribState {
return false;
}
/**
* Returns true if any currently enabled vertex attribute was registered without a VBO
* (i.e. as a client-side pointer). In core profile, such attribs are treated as null
* offsets into a non-existent buffer, causing a native crash at draw time.
*/
public static boolean hasAnyClientSideEnabledAttrib() {
return clientSideEnabledCount > 0;
}
public static class Attrib {
public boolean enabled;
public int size;
@@ -102,6 +133,10 @@ public class VertexAttribState {
public int vboId;
public ByteBuffer clientPointer;
public boolean isClientSide() {
return enabled && clientPointer != null;
}
public void reset() {
enabled = false;
size = 0;
@@ -156,6 +156,57 @@ class FeedbackManagerTest {
GLStateManager.glDeleteVertexArrays(vao);
}
@Test
void testPolygonFeedback_GL2D() {
final FloatBuffer buf = BufferUtils.createFloatBuffer(128);
FeedbackManager.glFeedbackBuffer(GL11.GL_2D, buf);
FeedbackManager.glRenderMode(GL11.GL_FEEDBACK);
GLStateManager.getModelViewMatrix().identity();
GLStateManager.getProjectionMatrix().identity();
GLStateManager.getViewportState().setViewPort(0, 0, 800, 600);
GLStateManager.getViewportState().setDepthRange(0.0, 1.0);
final int vao = GL30.glGenVertexArrays();
GLStateManager.glBindVertexArray(vao);
final float[] verts = {
0f, 0f, 0f,
1f, 0f, 0f,
1f, 1f, 0f,
0f, 1f, 0f
};
final FloatBuffer vertBuf = BufferUtils.createFloatBuffer(verts.length);
vertBuf.put(verts).flip();
final int vbo = GL15.glGenBuffers();
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertBuf, GL15.GL_STATIC_DRAW);
GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 12, 0);
GLStateManager.glEnableVertexAttribArray(0);
FeedbackManager.processDrawArrays(GL11.GL_POLYGON, 0, 4);
final int count = FeedbackManager.glRenderMode(GL11.GL_RENDER);
assertEquals(10, count, "Polygon in GL_2D should produce 10 floats");
assertEquals(GL11.GL_POLYGON_TOKEN, buf.get(0), 0.001f);
assertEquals(4.0f, buf.get(1), 0.001f);
assertEquals(400.0f, buf.get(2), 0.01f);
assertEquals(300.0f, buf.get(3), 0.01f);
assertEquals(800.0f, buf.get(4), 0.01f);
assertEquals(300.0f, buf.get(5), 0.01f);
assertEquals(800.0f, buf.get(6), 0.01f);
assertEquals(600.0f, buf.get(7), 0.01f);
assertEquals(400.0f, buf.get(8), 0.01f);
assertEquals(600.0f, buf.get(9), 0.01f);
GLStateManager.glDisableVertexAttribArray(0);
GLStateManager.glBindVertexArray(0);
GL15.glDeleteBuffers(vbo);
GLStateManager.glDeleteVertexArrays(vao);
}
@Test
void testIdentityTransform_viewportMapping() {
final FloatBuffer buf = BufferUtils.createFloatBuffer(64);
@@ -0,0 +1,142 @@
package com.gtnewhorizons.angelica.glsm.redirect;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.ArrayList;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class GLSMRedirectorTest {
private static final String GLSM = GLSMRedirector.getTargetClassName();
private static final Handle LAMBDA_METAFACTORY = new Handle(
Opcodes.H_INVOKESTATIC,
"java/lang/invoke/LambdaMetafactory",
"metafactory",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;"
+ "Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)"
+ "Ljava/lang/invoke/CallSite;",
false);
private static ClassNode makeClassWithInvokeDynamic(Handle implHandle) {
final ClassNode cn = new ClassNode();
cn.version = Opcodes.V1_8;
cn.access = Opcodes.ACC_PUBLIC;
cn.name = "com/example/TestClass";
cn.superName = "java/lang/Object";
cn.methods = new ArrayList<>();
final MethodNode mn = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "test", "()V", null, null);
mn.instructions.add(new InvokeDynamicInsnNode(
"run",
"()Ljava/lang/Runnable;",
LAMBDA_METAFACTORY,
Type.getType("()V"),
implHandle,
Type.getType("()V")));
mn.instructions.add(new InsnNode(Opcodes.RETURN));
cn.methods.add(mn);
return cn;
}
private static Handle getResultHandle(ClassNode cn) {
final InvokeDynamicInsnNode dyn = (InvokeDynamicInsnNode) cn.methods.get(0).instructions.get(0);
return (Handle) dyn.bsmArgs[1];
}
@Test
void invokeDynamicGL11HandleIsRedirected() {
final Handle impl = new Handle(Opcodes.H_INVOKESTATIC, "org/lwjgl/opengl/GL11", "glPopMatrix", "()V", false);
final ClassNode cn = makeClassWithInvokeDynamic(impl);
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertTrue(changed);
final Handle result = getResultHandle(cn);
assertEquals(GLSM, result.getOwner());
assertEquals("glPopMatrix", result.getName());
assertEquals("()V", result.getDesc());
assertEquals(Opcodes.H_INVOKESTATIC, result.getTag());
}
@Test
void invokeDynamicNamedClassHandleIsRedirected() {
final Handle impl = new Handle(Opcodes.H_INVOKESTATIC, "org/lwjgl/opengl/EXTBlendFuncSeparate", "glBlendFuncSeparateEXT", "(IIII)V", false);
final ClassNode cn = makeClassWithInvokeDynamic(impl);
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertTrue(changed);
final Handle result = getResultHandle(cn);
assertEquals(GLSM, result.getOwner());
assertEquals("tryBlendFuncSeparate", result.getName());
assertEquals("(IIII)V", result.getDesc());
}
@Test
void invokeDynamicNonGLHandleIsNotTouched() {
final Handle impl = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
final ClassNode cn = makeClassWithInvokeDynamic(impl);
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertFalse(changed);
final Handle result = getResultHandle(cn);
assertEquals("java/lang/System", result.getOwner());
assertEquals("currentTimeMillis", result.getName());
}
@Test
void invokeDynamicUnknownGLMethodIsNotTouched() {
final Handle impl = new Handle(Opcodes.H_INVOKESTATIC, "org/lwjgl/opengl/GL11", "glNonexistent", "()V", false);
final ClassNode cn = makeClassWithInvokeDynamic(impl);
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertFalse(changed);
final Handle result = getResultHandle(cn);
assertEquals("org/lwjgl/opengl/GL11", result.getOwner());
}
@Test
void invokeDynamicGLCVariantIsRedirected() {
final Handle impl = new Handle(Opcodes.H_INVOKESTATIC, "org/lwjgl/opengl/GL11C", "glDrawArrays", "(III)V", false);
final ClassNode cn = makeClassWithInvokeDynamic(impl);
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertTrue(changed);
final Handle result = getResultHandle(cn);
assertEquals(GLSM, result.getOwner());
assertEquals("glDrawArrays", result.getName());
assertEquals("(III)V", result.getDesc());
}
@Test
void transformedClassProducesValidBytecode() {
final Handle impl = new Handle(Opcodes.H_INVOKESTATIC, "org/lwjgl/opengl/GL11", "glPopMatrix", "()V", false);
final ClassNode cn = makeClassWithInvokeDynamic(impl);
new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
assertDoesNotThrow(() -> {
cn.accept(cw);
final byte[] bytes = cw.toByteArray();
assertTrue(bytes.length > 0);
});
}
}
@@ -1,17 +1,11 @@
package com.gtnewhorizons.angelica;
import com.gtnewhorizons.angelica.common.BlockError;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.config.ConfigMigrator;
import com.gtnewhorizons.angelica.proxy.CommonProxy;
import com.gtnewhorizons.angelica.utils.AnimationMode;
import com.gtnewhorizons.angelica.utils.ManagedEnum;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -32,32 +26,19 @@ import static com.gtnewhorizons.angelica.AngelicaMod.MOD_ID;
acceptableRemoteVersions = "*",
guiFactory = "com.gtnewhorizons.angelica.config.AngelicaGuiConfigFactory")
public class AngelicaMod {
public static final String MOD_ID = "angelica";
public static final Logger LOGGER = LogManager.getLogger("Angelica");
public static final boolean lwjglDebug = Boolean.getBoolean("org.lwjgl.util.Debug");
private static SodiumGameOptions CONFIG;
public static SodiumGameOptions options() {
if (CONFIG == null) {
CONFIG = SodiumGameOptions.load(ConfigMigrator.handleConfigMigration("angelica-options.json"));
}
return CONFIG;
}
@SidedProxy(clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy", serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy")
@SidedProxy(
clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy",
serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy")
public static CommonProxy proxy;
public static final boolean lwjglDebug = Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false"));
public static final ManagedEnum<AnimationMode> animationsMode = new ManagedEnum<>(AnimationMode.VISIBLE_ONLY);
public static BlockError blockError;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
ModStatus.preInit();
proxy.preInit(event);
blockError = new BlockError();
}
@Mod.EventHandler
@@ -0,0 +1,118 @@
package com.gtnewhorizons.angelica.api;
import com.gtnewhorizons.angelica.glsm.redirect.GLSMRedirector;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import java.util.regex.Pattern;
/**
* Public API for querying Angelica's GL call redirections.
* <p>
* Angelica's bytecode transformer redirects GL calls (e.g., {@code GL11.glPushMatrix()}) to
* {@link com.gtnewhorizons.angelica.glsm.GLStateManager GLStateManager} for state tracking and
* core profile compatibility. This works for normal Java bytecode loaded through the Forge classloader,
* but callers that bypass class transformation (e.g., Nashorn/script engines, reflection, MethodHandles)
* need to perform their own redirection.
* <p>
* This class provides the redirect mapping data and a precompiled regex pattern for transforming
* script source text before evaluation.
*
* <h3>Example: transforming a Nashorn script before eval</h3>
* Given a script that uses {@code importPackage(Packages.org.lwjgl.opengl)} and calls
* {@code GL11.glPushMatrix()}, the text transformation rewrites those calls before evaluation:
* <pre>{@code
* // Make GLStateManager available to the script -- either via importPackage:
* script = "importPackage(Packages.com.gtnewhorizons.angelica.glsm);\n" + script;
* // ... or via Java.type for an explicit binding:
* // script = "var GLStateManager = Java.type('" + GLRedirects.TARGET_CLASS + "');\n" + script;
*
* // Rewrite: GL11.glPushMatrix() -> GLStateManager.glPushMatrix()
* script = GLRedirects.getMethodRedirectPattern().matcher(script).replaceAll(mr -> {
* String target = GLRedirects.getTargetMethodName(mr.group(0));
* return target != null ? "GLStateManager." + target : mr.group(0);
* });
*
* engine.eval(script);
* }</pre>
*/
public final class GLRedirects {
/** Fully qualified name of the GLStateManager class that all methods redirect to. */
@SuppressWarnings("unused")
public static final String TARGET_CLASS = "com.gtnewhorizons.angelica.glsm.GLStateManager";
private static final String SHORT_GL_PREFIX;
private static final Map<String, Map<String, String>> NAMED_CLASS_SHORT_NAME_MAP;
private static final Map<String, String> GL_PREFIX_METHOD_REDIRECTS;
private static final Pattern METHOD_REDIRECT_PATTERN;
static {
SHORT_GL_PREFIX = buildShortGLPrefix();
NAMED_CLASS_SHORT_NAME_MAP = buildNamedClassShortNameMap();
GL_PREFIX_METHOD_REDIRECTS = GLSMRedirector.getGLPrefixMethodRedirects();
METHOD_REDIRECT_PATTERN = buildMethodRedirectPattern();
}
private GLRedirects() {}
/**
* Returns a precompiled pattern that matches redirected {@code ClassName.methodName} references
* using short (simple) class names, as they might typically appear in script text.
*
* @return compiled regex pattern
*/
public static Pattern getMethodRedirectPattern() {
return METHOD_REDIRECT_PATTERN;
}
/**
* Looks up the GLStateManager target method name for a short-name reference.
*
* @param classAndMethod short class name and method, e.g., {@code "GL11.glPushMatrix"}
* @return the target method name on GLStateManager (e.g., {@code "glPushMatrix"}), or {@code null} if this reference is not redirected
*/
public static String getTargetMethodName(String classAndMethod) {
final int dot = classAndMethod.indexOf('.');
if (dot < 0) return null;
final String className = classAndMethod.substring(0, dot);
final String methodName = classAndMethod.substring(dot + 1);
final Map<String, String> classRedirects = NAMED_CLASS_SHORT_NAME_MAP.get(className);
if (classRedirects != null) {
return classRedirects.get(methodName);
}
if (className.startsWith(SHORT_GL_PREFIX)) {
return GL_PREFIX_METHOD_REDIRECTS.get(methodName);
}
return null;
}
private static String buildShortGLPrefix() {
final String glPrefix = GLSMRedirector.getGLPrefix();
return glPrefix.substring(glPrefix.lastIndexOf('/') + 1);
}
private static Map<String, Map<String, String>> buildNamedClassShortNameMap() {
final Map<String, Map<String, String>> named = new HashMap<>();
for (final var entry : GLSMRedirector.getNamedClassMethodRedirects().entrySet()) {
final String internalName = entry.getKey();
final String shortName = internalName.substring(internalName.lastIndexOf('/') + 1);
named.put(shortName, entry.getValue());
}
return named;
}
private static Pattern buildMethodRedirectPattern() {
final TreeSet<String> alternatives = new TreeSet<>();
alternatives.add(Pattern.quote(SHORT_GL_PREFIX) + "\\w+");
for (final String shortName : NAMED_CLASS_SHORT_NAME_MAP.keySet()) {
alternatives.add(Pattern.quote(shortName));
}
final String classAlt = String.join("|", alternatives);
return Pattern.compile("\\b(" + classAlt + ")\\.\\w+\\b");
}
}
@@ -334,6 +334,7 @@ public class BatchingFontRenderer {
batchCommands.sort(FontDrawCmd.DRAW_ORDER_COMPARATOR);
final boolean isTextureEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
final boolean isBlendEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_BLEND);
final int boundTextureBefore = GLStateManager.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
boolean textureChanged = false;
@@ -417,6 +418,9 @@ public class BatchingFontRenderer {
if (isTextureEnabledBefore) {
GLStateManager.glEnable(GL11.GL_TEXTURE_2D);
}
if (!isBlendEnabledBefore) {
GLStateManager.disableBlend();
}
if (textureChanged) {
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, boundTextureBefore);
}
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.client.rendering;
import com.github.bsideup.jabel.Desugar;
import com.gtnewhorizon.gtnhlib.client.renderer.DirectTessellator;
import com.gtnewhorizon.gtnhlib.client.renderer.ITessellatorInstance;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
@@ -33,10 +34,30 @@ class DeferredBatchTessellator extends DirectTessellator {
private final Vector3f scratch = new Vector3f();
private Matrix4fc currentTransform;
private Tessellator parentTessellator;
private boolean inIntercept;
DeferredBatchTessellator(ByteBuffer buffer) {
super(buffer, false); // deleteAfter=false: keep buffer across resets for reuse
}
void setParentTessellator(Tessellator parent) {
this.parentTessellator = parent;
}
@Override
public int draw() {
if (!inIntercept) {
final Tessellator parent = parentTessellator;
if (parent != null && parent.isDrawing) {
interceptDraw(parent);
((ITessellatorInstance) parent).discard();
}
}
isDrawing = false;
return 0;
}
@Override
protected long writeVertexData(VertexFormat format, int[] rawBuffer, int rawBufferIndex) {
if (currentTransform != null) {
@@ -53,27 +74,32 @@ class DeferredBatchTessellator extends DirectTessellator {
@Override
protected int interceptDraw(Tessellator tess) {
// Compute delta: if current MV differs from default, pre-transform vertices
final Matrix4f currentMV = GLStateManager.getModelViewMatrix();
if (!currentMV.equals(defaultModelview)) {
defaultModelviewInverse.mul(currentMV, deltaMatrix);
this.currentTransform = deltaMatrix;
} else {
this.currentTransform = null;
inIntercept = true;
try {
// Compute delta: if current MV differs from default, pre-transform vertices
final Matrix4f currentMV = GLStateManager.getModelViewMatrix();
if (!currentMV.equals(defaultModelview)) {
defaultModelviewInverse.mul(currentMV, deltaMatrix);
this.currentTransform = deltaMatrix;
} else {
this.currentTransform = null;
}
final int byteOffsetBefore = bufferLimit();
final int vertCount = tess.vertexCount;
final int drawMode = tess.drawMode;
final int flags = VertexFlags.convertToFlags(tess.hasTexture, tess.hasColor, tess.hasNormals, tess.hasBrightness);
final long stateKey = DeferredDrawBatcher.captureStateKey();
final int result = super.interceptDraw(tess); // repacks int[] -> ByteBuffer + transforms if vertexTransform set
final int byteOffsetAfter = bufferLimit();
ranges.add(new DrawRange(stateKey, byteOffsetBefore, byteOffsetAfter - byteOffsetBefore, vertCount, drawMode, flags));
this.currentTransform = null; // clear for next draw
return result;
} finally {
inIntercept = false;
}
final int byteOffsetBefore = bufferLimit();
final int vertCount = tess.vertexCount;
final int drawMode = tess.drawMode;
final int flags = VertexFlags.convertToFlags(tess.hasTexture, tess.hasColor, tess.hasNormals, tess.hasBrightness);
final long stateKey = DeferredDrawBatcher.captureStateKey();
final int result = super.interceptDraw(tess); // repacks int[] → ByteBuffer + transforms if vertexTransform set
final int byteOffsetAfter = bufferLimit();
ranges.add(new DrawRange(stateKey, byteOffsetBefore, byteOffsetAfter - byteOffsetBefore, vertCount, drawMode, flags));
this.currentTransform = null; // clear for next draw
return result;
}
List<DrawRange> getRanges() { return ranges; }
@@ -86,6 +112,7 @@ class DeferredBatchTessellator extends DirectTessellator {
@Override
protected void onRemovedFromStack() {
parentTessellator = null;
clearRanges();
super.onRemovedFromStack(); // calls reset(), keeps baseBuffer (deleteAfter=false)
}
@@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.client.rendering;
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import lombok.Getter;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.opengl.GL11;
import java.util.Comparator;
@@ -37,6 +38,7 @@ public class DeferredDrawBatcher {
batchTessellator = new DeferredBatchTessellator(memAlloc(INITIAL_BUFFER_SIZE));
}
batchTessellator.clearRanges();
batchTessellator.setParentTessellator(Tessellator.instance);
batchTessellator.snapshotDefaultModelview();
TessellatorManager.startCapturingDirect(batchTessellator);
}
@@ -99,10 +101,14 @@ public class DeferredDrawBatcher {
totalBytes += e.byteLength();
totalVertices += e.vertexCount();
subEnd++;
// Don't try to merge strips, fans, loops or polygons
if (drawMode == GL11.GL_TRIANGLE_STRIP || drawMode == GL11.GL_TRIANGLE_FAN || drawMode == GL11.GL_LINE_STRIP ||
drawMode == GL11.GL_LINE_LOOP || drawMode == GL11.GL_QUAD_STRIP || drawMode == GL11.GL_POLYGON)
break;
}
TessellatorStreamingDrawer.drawPackedBatch(
batchTessellator, ranges, i, subEnd, totalBytes, totalVertices, drawMode, flags);
TessellatorStreamingDrawer.drawPackedBatch(batchTessellator, ranges, i, subEnd, totalBytes, totalVertices, drawMode, flags);
i = subEnd;
}
@@ -1,10 +1,8 @@
package com.gtnewhorizons.angelica.client.rendering;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
import net.minecraft.client.renderer.texture.AbstractTexture;
import org.jetbrains.annotations.Nullable;
@@ -15,11 +13,15 @@ public class TextureTracker {
*/
public static final TextureTracker INSTANCE = new TextureTracker();
private static Runnable bindTextureListener;
static {
StateUpdateNotifiers.bindTextureNotifier = listener -> bindTextureListener = listener;
}
private final Int2ObjectMap<AbstractTexture> textures = new Int2ObjectOpenHashMap<>();
private boolean lockBindCallback;
private TextureTracker() {
}
@@ -31,23 +33,13 @@ public class TextureTracker {
public AbstractTexture getTexture(int id) {
return textures.get(id);
}
public void onBindTexture(int id) {
if (lockBindCallback) {
return;
}
if (GLStateManager.getActiveTextureUnit() == 0) {
lockBindCallback = true;
if (GLSMHooks.TEXTURE_BIND.hasListeners()) {
GLSMHooks.textureBindEvent.textureId = id;
GLSMHooks.TEXTURE_BIND.post(GLSMHooks.textureBindEvent);
}
// Reset texture state
RenderSystem.bindTextureToUnit(0, id);
lockBindCallback = false;
public void onBindTexture() {
if (bindTextureListener != null) {
bindTextureListener.run();
}
}
public void onDeleteTexture(int id) {
textures.remove(id);
}
@@ -25,6 +25,7 @@ public class ModStatus {
public static boolean isThaumicHorizonsLoaded;
public static boolean isBaublesLoaded;
public static boolean isFluidLoggedLoaded;
public static boolean isBOPLoaded;
public static void preInit() {
if (Loader.isModLoaded("backhand")) {
@@ -45,6 +46,7 @@ public class ModStatus {
isFluidLoggedLoaded = Loader.isModLoaded("fluidlogged");
isHoloInventoryLoaded = Loader.isModLoaded("holoinventory");
isBOPLoaded = Loader.isModLoaded("BiomesOPlenty");
// remove compat with original release of BG2
if (isBattlegearLoaded){
@@ -1,34 +1,33 @@
package com.gtnewhorizons.angelica.compat.bettercrashes;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt;
import cpw.mods.fml.common.Optional;
import net.minecraft.client.Minecraft;
import vfyjxf.bettercrashes.utils.StateManager;
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
@Optional.Interface(modid = "angelica", iface = "vfyjxf.bettercrashes.utils.StateManager.IResettable")
public class BetterCrashesCompat implements StateManager.IResettable {
private static BetterCrashesCompat INSTANCE;
public BetterCrashesCompat() {
AngelicaMod.LOGGER.info("BetterCrashesCompat initialized");
this.register();
}
public static void init() {
if (INSTANCE == null) {
INSTANCE = new BetterCrashesCompat();
}
}
public BetterCrashesCompat() {
LOGGER.info("BetterCrashesCompat initialized");
this.register();
}
@Override
public void resetState() {
LOGGER.info("Reloading SodiumRenderer");
AngelicaMod.LOGGER.info("Reloading SodiumRenderer");
((IRenderGlobalExt) Minecraft.getMinecraft().renderGlobal).angelica$reload();
LOGGER.info("Resetting GLStateManager");
AngelicaMod.LOGGER.info("Resetting GLStateManager");
GLStateManager.reset();
}
}
@@ -262,6 +262,11 @@ public class AngelicaConfig {
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public boolean narrowAlfheim;
@Config.Comment("Narrow Ears transformer exclusions to allow GL redirection")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public boolean narrowEars;
}
@Config.Comment("Renders chunks before neighbors are ready. Improves loading at render distance edges, useful for low render distance servers.")
@@ -25,6 +25,7 @@ import net.minecraft.client.renderer.EntityRenderer;
import net.minecraftforge.client.GuiIngameForge;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import thaumcraft.common.Thaumcraft;
import xaero.common.core.XaeroMinimapCore;
@@ -69,6 +70,12 @@ public class HUDCaching {
XaeroMinimapCore.beforeIngameGuiRender(partialTicks);
}
GLStateManager.disableLighting();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.disableTexture();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.enableTexture();
if (!AngelicaConfig.hudCachingActive || !GLStateManager.isFramebufferEnabled()) {
ingame.renderGameOverlay(partialTicks, hasScreen, mouseX, mouseY);
return;
@@ -1,5 +1,6 @@
package com.gtnewhorizons.angelica.iris;
import com.gtnewhorizons.angelica.client.rendering.TextureTracker;
import com.gtnewhorizons.angelica.glsm.hooks.DeferredAlphaHandler;
import com.gtnewhorizons.angelica.glsm.hooks.DeferredBlendHandler;
import com.gtnewhorizons.angelica.glsm.hooks.DeferredDepthColorHandler;
@@ -10,13 +11,29 @@ import net.coderbot.iris.gl.blending.AlphaTestStorage;
import net.coderbot.iris.gl.blending.BlendModeStorage;
import net.coderbot.iris.gl.blending.DepthColorStorage;
import net.coderbot.iris.gl.program.ProgramUniforms;
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.texture.pbr.PBRTextureManager;
import net.coderbot.iris.vertices.ImmediateState;
public class IrisGLSMBridge {
private static Runnable blendFuncListener = null;
private static Runnable fogModeListener = null;
private static Runnable fogStartListener = null;
private static Runnable fogEndListener = null;
private static Runnable fogDensityListener = null;
static {
StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener;
StateUpdateNotifiers.fogModeNotifier = listener -> fogModeListener = listener;
StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener;
StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener;
StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener;
}
public static void register() {
IrisSamplers.initRenderer();
GLSMHooks.blendHandler = new DeferredBlendHandler() {
@@ -74,9 +91,25 @@ public class IrisGLSMBridge {
DepthColorStorage.deferColorMask(r, g, b, a);
}
};
GLSMHooks.BLEND_FUNC_CHANGE.addListener(event -> {
if (Iris.enabled) {
if (blendFuncListener != null) blendFuncListener.run();
}
});
GLSMHooks.FOG_STATE_CHANGE.addListener(event -> {
if (Iris.enabled) {
if (fogModeListener != null) fogModeListener.run();
if (fogStartListener != null) fogStartListener.run();
if (fogEndListener != null) fogEndListener.run();
if (fogDensityListener != null) fogDensityListener.run();
}
});
GLSMHooks.TEXTURE_BIND.addListener(event -> {
if (Iris.enabled) {
TextureTracker.INSTANCE.onBindTexture();
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
if (pipeline != null) {
pipeline.onBindTexture(event.textureId);
@@ -114,10 +147,10 @@ public class IrisGLSMBridge {
if (!drp.shouldOverrideShaders()) return;
if (drp.getActivePassProgramId() == -1) return;
if (DepthColorStorage.isOwnedProgram(event.newProgram)) {
if (!ImmediateState.isRenderingLevel || DepthColorStorage.isOwnedProgram(event.newProgram)) {
DepthColorStorage.unlockDepthColor();
} else {
DepthColorStorage.disableDepthColor();
drp.onModProgramOverride();
}
});
}
@@ -0,0 +1,227 @@
package com.gtnewhorizons.angelica.loading;
import com.gtnewhorizon.gtnhlib.config.ConfigException;
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import com.gtnewhorizon.gtnhmixins.builders.ITransformers;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.config.CompatConfig;
import com.gtnewhorizons.angelica.config.FontConfig;
import com.gtnewhorizons.angelica.loading.fml.compat.CompatHandlers;
import com.gtnewhorizons.angelica.mixins.Mixins;
import com.gtnewhorizons.retrofuturabootstrap.SharedConfig;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import jss.notfine.asm.AsmTransformers;
import jss.notfine.asm.mappings.Namer;
import jss.notfine.config.MCPatcherForgeConfig;
import jss.notfine.config.NotFineConfig;
import net.minecraft.launchwrapper.Launch;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.spongepowered.asm.launch.GlobalProperties;
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
// this is not the real IFMLLoadingPlugin, if you put any annotations
// here it won't do anything, that's why we register transformer
// exclusions manually in the constructor
public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
public static final Logger LOGGER = LogManager.getLogger("Angelica");
private static Boolean OBF_ENV;
private String[] transformerClasses;
public AngelicaClientTweaker() {
Launch.classLoader.addTransformerExclusion("jss.notfine.asm");
Launch.classLoader.addTransformerExclusion("com.gtnewhorizons.angelica.loading");
Launch.classLoader.addTransformerExclusion("com.gtnewhorizons.angelica.glsm.GLStateManager");
if (Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE) {
addLwjgl3ifyExclusions();
}
try {
// Angelica Config
ConfigurationManager.registerConfig(AngelicaConfig.class);
ConfigurationManager.registerConfig(CompatConfig.class);
ConfigurationManager.registerConfig(FontConfig.class);
MCPatcherForgeConfig.registerConfig();
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
final LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
if (AngelicaConfig.enableDebugLogging) {
loggerConfig.setLevel(Level.DEBUG);
}
ctx.updateLoggers();
// Debug features
AngelicaConfig.enableTestBlocks = Boolean.getBoolean("angelica.enableTestBlocks");
} catch (ConfigException e) {
throw new RuntimeException(e);
}
verifyDependencies();
// Register a scoped redirector early so classes prematurely loaded by other coremods during discovery/injectData
// (e.g. Mycelium using HookLoader.class.getName()) still get GL calls redirected to GLSM. Only targets specific mod
// packages to avoid interfering with mixin delegation on game classes. AngelicaLateTweaker removes this registration once
// mixins are setup.
if (FMLLaunchHandler.side().isClient()) {
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
if (!rfbLoaded) {
Launch.classLoader.registerTransformer("com.gtnewhorizons.angelica.loading.fml.transformers.EarlyRedirectorTransformer");
}
}
}
private static void addLwjgl3ifyExclusions() {
final var handle = SharedConfig.getRfbTransformers().stream()
.filter(transformer -> transformer.id().equals("lwjgl3ify:redirect"))
.findFirst()
.orElse(null);
if (handle != null) {
handle.exclusions().add("org.embeddedt.embeddium");
handle.exclusions().add("org.taumc.celeritas");
handle.exclusions().add("com.mitchej123.lwjgl.lwjgl3");
handle.exclusions().add("com.mitchej123.glsm");
handle.exclusions().add("com.gtnewhorizons.angelica.lwjgl3");
handle.exclusions().add("com.gtnewhorizons.angelica.vulkan");
}
}
private static void verifyDependencies() {
// Check for fastutil (bundled with GTNHLib since 0.2.1)
if (AngelicaTweaker.class.getResource("/it/unimi/dsi/fastutil/ints/Int2ObjectMap.class") == null) {
throw new RuntimeException("Missing dependency: Angelica requires GTNHLib! Download: https://modrinth.com/mod/gtnhlib");
}
// Check for PrimitiveExtractor/cel.model classes (added in GTNHLib 0.8.21)
if (AngelicaTweaker.class.getResource("/com/gtnewhorizon/gtnhlib/client/renderer/PrimitiveExtractor.class") == null) {
throw new RuntimeException("GTNHLib is outdated: Angelica requires GTNHLib 0.8.21 or newer! Download: https://modrinth.com/mod/gtnhlib");
}
// Check for jvmdowngrader stubs (bundled with GTNHLib since 0.9.0)
if (AngelicaTweaker.class.getResource("/xyz/wagyourtail/jvmdg/exc/MissingStubError.class") == null) {
throw new RuntimeException("GTNHLib is outdated: Angelica requires GTNHLib 0.9.0 or newer! Download: https://modrinth.com/mod/gtnhlib");
}
}
@Override
public String[] getASMTransformerClass() {
if (transformerClasses == null) {
final List<String> transformers = new ArrayList<>();
transformers.addAll(CompatHandlers.getTransformers());
// Add NotFine transformers
final List<String> notFineTransformers = Arrays.asList(ITransformers.getTransformers(AsmTransformers.class));
if (!notFineTransformers.isEmpty()) Namer.initNames();
transformers.addAll(notFineTransformers);
transformerClasses = transformers.toArray(new String[0]);
}
return transformerClasses;
}
@Override
public String getModContainerClass() {
return null;
}
@Override
public String getSetupClass() {
return null;
}
@Override
public void injectData(Map<String, Object> data) {
OBF_ENV = (Boolean) data.get("runtimeDeobfuscationEnabled");
// Directly add this to the MixinServiceLaunchWrapper tweaker's list of Tweak Classes
final List<String> tweaks = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES);
if (tweaks != null) {
// Bridge transformer compat config to blackboard for AngelicaLateTweaker
narrowTransformerConfig("DragonAPI", AngelicaConfig.transformerCompat.narrowDragonAPI);
narrowTransformerConfig("Xaeros", AngelicaConfig.transformerCompat.narrowXaeros);
narrowTransformerConfig("AdvancedLightsabers", AngelicaConfig.transformerCompat.narrowAdvancedLightsabers);
narrowTransformerConfig("Alfheim", AngelicaConfig.transformerCompat.narrowAlfheim);
narrowTransformerConfig("Ears", AngelicaConfig.transformerCompat.narrowEars);
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.IncompatibleModsDisablerTweaker");
if (AngelicaConfig.enableHudCaching) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.XaerosTransformerDisablerTweaker");
}
if (FMLLaunchHandler.side().isClient()) {
// We register ITweakers that will run last in order to register
// specific IClassTransformers that will run last in the transformer chain.
// If we were to register them normally in getASMTransformerClass(),
// they would be sorted at index 0 which we do not want.
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
if (!rfbLoaded) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.AngelicaLateTweaker");
if (AngelicaConfig.enableCeleritas) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.CeleritasLateTweaker");
}
}
}
}
}
/** Publish a transformer-narrowing toggle to the blackboard; read by AngelicaLateTweaker.narrowEnabled(). */
private static void narrowTransformerConfig(String mod, boolean enabled) {
Launch.blackboard.put("angelica.narrow." + mod, enabled);
}
@Override
public String getAccessTransformerClass() {
return null;
}
@Override
public String getMixinConfig() {
final int v = Runtime.version().feature();
if (v >= 21) return "mixins.angelica.early.j21.json";
if (v >= 17) return "mixins.angelica.early.j17.json";
return "mixins.angelica.early.json";
}
@Override
public List<String> getMixins(Set<String> loadedCoreMods) {
NotFineConfig.loadSettings();
//This may be possible to handle differently or fix.
if (loadedCoreMods.contains("cofh.asm.LoadingPlugin")) {
MCPatcherForgeConfig.ExtendedHD.hdFont = false;
}
return IMixins.getEarlyMixins(Mixins.class, loadedCoreMods);
}
/**
* Returns true if we are in an obfuscated environment, returns false in dev environment.
*/
public static boolean isObfEnv() {
if (OBF_ENV == null) {
throw new IllegalStateException("Obfuscation state has been accessed too early!");
}
return OBF_ENV;
}
/**
* Returns the appropriate name according to current environment's obfuscation
*/
public static String obf(String deobf, String obf) {
if (OBF_ENV == null) {
throw new IllegalStateException("Obfuscation state has been accessed too early!");
}
if (OBF_ENV) {
return obf;
}
return deobf;
}
}
@@ -1,34 +1,12 @@
package com.gtnewhorizons.angelica.loading;
import com.gtnewhorizon.gtnhlib.config.ConfigException;
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import com.gtnewhorizon.gtnhmixins.builders.ITransformers;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.config.CompatConfig;
import com.gtnewhorizons.angelica.config.FontConfig;
import com.gtnewhorizons.angelica.mixins.Mixins;
import com.gtnewhorizons.angelica.loading.fml.compat.CompatHandlers;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import jss.notfine.asm.AsmTransformers;
import jss.notfine.asm.mappings.Namer;
import jss.notfine.config.MCPatcherForgeConfig;
import jss.notfine.config.NotFineConfig;
import com.gtnewhorizons.retrofuturabootstrap.SharedConfig;
import net.minecraft.launchwrapper.Launch;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.spongepowered.asm.launch.GlobalProperties;
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -41,195 +19,76 @@ import java.util.Set;
// They will instead use default index 0 which means they will see
// obfuscated mappings and not SRG mappings when running outside of dev env.
// ===============================================
//@IFMLLoadingPlugin.SortingIndex(Integer.MAX_VALUE - 5)
@IFMLLoadingPlugin.MCVersion("1.7.10")
@IFMLLoadingPlugin.TransformerExclusions({
"jss.notfine.asm",
"com.gtnewhorizons.angelica.loading",
"com.gtnewhorizons.angelica.glsm.GLStateManager"
})
public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
private static Boolean OBF_ENV;
public static final Logger LOGGER = LogManager.getLogger("Angelica");
private String[] transformerClasses;
private final IFMLLoadingPlugin loadingPlugin;
private final IEarlyMixinLoader mixinLoader;
public AngelicaTweaker() {
if (Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE) {
addLwjgl3ifyExclusions();
}
try {
// Angelica Config
ConfigurationManager.registerConfig(AngelicaConfig.class);
ConfigurationManager.registerConfig(CompatConfig.class);
ConfigurationManager.registerConfig(FontConfig.class);
MCPatcherForgeConfig.registerConfig();
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
final LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
if (AngelicaConfig.enableDebugLogging) {
loggerConfig.setLevel(Level.DEBUG);
}
ctx.updateLoggers();
// Debug features
AngelicaConfig.enableTestBlocks = Boolean.getBoolean("angelica.enableTestBlocks");
} catch (ConfigException e) {
throw new RuntimeException(e);
}
verifyDependencies();
// Register a scoped redirector early so classes prematurely loaded by other coremods during discovery/injectData
// (e.g. Mycelium using HookLoader.class.getName()) still get GL calls redirected to GLSM. Only targets specific mod
// packages to avoid interfering with mixin delegation on game classes. AngelicaLateTweaker removes this registration once
// mixins are setup.
if (FMLLaunchHandler.side().isClient()) {
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
if (!rfbLoaded) {
Launch.classLoader.registerTransformer("com.gtnewhorizons.angelica.loading.fml.transformers.EarlyRedirectorTransformer");
}
}
}
private static void verifyDependencies() {
// Check for fastutil (bundled with GTNHLib since 0.2.1)
if (AngelicaTweaker.class.getResource("/it/unimi/dsi/fastutil/ints/Int2ObjectMap.class") == null) {
throw new RuntimeException("Missing dependency: Angelica requires GTNHLib! Download: https://modrinth.com/mod/gtnhlib");
}
// Check for PrimitiveExtractor/cel.model classes (added in GTNHLib 0.8.21)
if (AngelicaTweaker.class.getResource("/com/gtnewhorizon/gtnhlib/client/renderer/PrimitiveExtractor.class") == null) {
throw new RuntimeException("GTNHLib is outdated: Angelica requires GTNHLib 0.8.21 or newer! Download: https://modrinth.com/mod/gtnhlib");
}
// Check for jvmdowngrader stubs (bundled with GTNHLib since 0.9.0)
if (AngelicaTweaker.class.getResource("/xyz/wagyourtail/jvmdg/exc/MissingStubError.class") == null) {
throw new RuntimeException("GTNHLib is outdated: Angelica requires GTNHLib 0.9.0 or newer! Download: https://modrinth.com/mod/gtnhlib");
final AngelicaClientTweaker clientTweaker = new AngelicaClientTweaker();
loadingPlugin = clientTweaker;
mixinLoader = clientTweaker;
} else {
loadingPlugin = null;
mixinLoader = null;
LogManager.getLogger("Angelica").info("Trying to get more FPS on your server ? :kekw:");
}
}
@Override
public String[] getASMTransformerClass() {
if (transformerClasses == null) {
final List<String> transformers = new ArrayList<>();
transformers.addAll(CompatHandlers.getTransformers());
// Add NotFine transformers
final List<String> notFineTransformers = Arrays.asList(ITransformers.getTransformers(AsmTransformers.class));
if (!notFineTransformers.isEmpty()) Namer.initNames();
transformers.addAll(notFineTransformers);
transformerClasses = transformers.toArray(new String[0]);
if (this.loadingPlugin != null) {
return this.loadingPlugin.getASMTransformerClass();
}
return transformerClasses;
return null;
}
@Override
public String getModContainerClass() {
if (this.loadingPlugin != null) {
return this.loadingPlugin.getModContainerClass();
}
return null;
}
@Override
public String getSetupClass() {
if (this.loadingPlugin != null) {
return this.loadingPlugin.getSetupClass();
}
return null;
}
/** Publish a transformer-narrowing toggle to the blackboard; read by AngelicaLateTweaker.narrowEnabled(). */
private static void narrowTransformerConfig(String mod, boolean enabled) {
Launch.blackboard.put("angelica.narrow." + mod, enabled);
}
@Override
public void injectData(Map<String, Object> data) {
OBF_ENV = (Boolean) data.get("runtimeDeobfuscationEnabled");
// Directly add this to the MixinServiceLaunchWrapper tweaker's list of Tweak Classes
final List<String> tweaks = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES);
if (tweaks != null) {
// Bridge transformer compat config to blackboard for AngelicaLateTweaker
narrowTransformerConfig("DragonAPI", AngelicaConfig.transformerCompat.narrowDragonAPI);
narrowTransformerConfig("Xaeros", AngelicaConfig.transformerCompat.narrowXaeros);
narrowTransformerConfig("AdvancedLightsabers", AngelicaConfig.transformerCompat.narrowAdvancedLightsabers);
narrowTransformerConfig("Alfheim", AngelicaConfig.transformerCompat.narrowAlfheim);
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.IncompatibleModsDisablerTweaker");
if (AngelicaConfig.enableHudCaching) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.XaerosTransformerDisablerTweaker");
}
if (FMLLaunchHandler.side().isClient()) {
// We register ITweakers that will run last in order to register
// specific IClassTransformers that will run last in the transformer chain.
// If we were to register them normally in getASMTransformerClass(),
// they would be sorted at index 0 which we do not want.
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
if (!rfbLoaded) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.AngelicaLateTweaker");
if (AngelicaConfig.enableCeleritas) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.CeleritasLateTweaker");
}
}
}
if (this.loadingPlugin != null) {
this.loadingPlugin.injectData(data);
}
}
@Override
public String getAccessTransformerClass() {
if (this.loadingPlugin != null) {
return this.loadingPlugin.getAccessTransformerClass();
}
return null;
}
@Override
public String getMixinConfig() {
final int v = Runtime.version().feature();
if (v >= 21) return "mixins.angelica.early.j21.json";
if (v >= 17) return "mixins.angelica.early.j17.json";
return "mixins.angelica.early.json";
if (this.mixinLoader != null) {
return this.mixinLoader.getMixinConfig();
}
return "mixins.angelica.server.json";
}
@Override
public List<String> getMixins(Set<String> loadedCoreMods) {
NotFineConfig.loadSettings();
//This may be possible to handle differently or fix.
if (loadedCoreMods.contains("cofh.asm.LoadingPlugin")) {
MCPatcherForgeConfig.ExtendedHD.hdFont = false;
if (this.mixinLoader != null) {
return this.mixinLoader.getMixins(loadedCoreMods);
}
return IMixins.getEarlyMixins(Mixins.class, loadedCoreMods);
}
private static void addLwjgl3ifyExclusions() {
final var handle = SharedConfig.getRfbTransformers().stream()
.filter(transformer -> transformer.id().equals("lwjgl3ify:redirect"))
.findFirst()
.orElse(null);
if (handle != null) {
handle.exclusions().add("org.embeddedt.embeddium");
handle.exclusions().add("org.taumc.celeritas");
handle.exclusions().add("com.mitchej123.lwjgl.lwjgl3");
handle.exclusions().add("com.mitchej123.glsm");
handle.exclusions().add("com.gtnewhorizons.angelica.lwjgl3");
handle.exclusions().add("com.gtnewhorizons.angelica.vulkan");
}
}
/**
* Returns true if we are in an obfuscated environment, returns false in dev environment.
*/
public static boolean isObfEnv() {
if (OBF_ENV == null) {
throw new IllegalStateException("Obfuscation state has been accessed too early!");
}
return OBF_ENV;
}
/**
* Returns the appropriate name according to current environment's obfuscation
*/
public static String obf(String deobf, String obf) {
if (OBF_ENV == null) {
throw new IllegalStateException("Obfuscation state has been accessed too early!");
}
if (OBF_ENV) {
return obf;
}
return deobf;
return Collections.emptyList();
}
}
@@ -1,6 +1,6 @@
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.lib.tree.AbstractInsnNode;
import org.spongepowered.asm.lib.tree.ClassNode;
@@ -62,7 +62,7 @@ public class FieldLevelTessellatorTransformer {
new FieldInsnNode(
Opcodes.GETSTATIC,
"net/minecraft/client/renderer/Tessellator",
AngelicaTweaker.obf("instance", "field_78398_a"),
AngelicaClientTweaker.obf("instance", "field_78398_a"),
"Lnet/minecraft/client/renderer/Tessellator;"));
list.add(new VarInsnNode(Opcodes.ASTORE, localIndex));
mn.instructions.insert(list);
@@ -1,6 +1,6 @@
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.lib.tree.ClassNode;
import org.spongepowered.asm.lib.tree.InsnList;
@@ -29,7 +29,7 @@ public class HUDCachingEarlyReturnTransformer {
} else if (method.desc.endsWith("V")) {
list.add(new InsnNode(Opcodes.RETURN));
} else {
AngelicaTweaker.LOGGER.warn(
AngelicaClientTweaker.LOGGER.warn(
"HUDCaching Conditional Return - Unknown return type: {}#{}:{}", cn.name, method.name, method.desc
);
return;
@@ -1,6 +1,6 @@
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.lib.tree.AbstractInsnNode;
import org.spongepowered.asm.lib.tree.ClassNode;
@@ -59,7 +59,7 @@ public class TileEntityNullGuardTransformer {
AbstractInsnNode in = mn.instructions.get(i);
if (in instanceof MethodInsnNode min) {
if (min.getOpcode() == Opcodes.INVOKEINTERFACE
&& min.name.equals(AngelicaTweaker.obf("getTileEntity", "func_147438_o"))
&& min.name.equals(AngelicaClientTweaker.obf("getTileEntity", "func_147438_o"))
&& min.owner.equals("net/minecraft/world/IBlockAccess")) {
AbstractInsnNode castNodeAbstract = min.getNext();
if (castNodeAbstract instanceof TypeInsnNode castNodeType) {
@@ -77,7 +77,7 @@ public class TileEntityNullGuardTransformer {
} else if (mn.desc.endsWith("V")) {
list.add(new InsnNode(Opcodes.RETURN));
} else {
AngelicaTweaker.LOGGER.warn("TileEntityNullGuard - Unknown Return Type: {}:{}", mn.name, mn.desc);
AngelicaClientTweaker.LOGGER.warn("TileEntityNullGuard - Unknown Return Type: {}:{}", mn.name, mn.desc);
return;
}
list.add(exit);
@@ -1,6 +1,6 @@
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.specific;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
import net.minecraft.launchwrapper.IClassTransformer;
import org.spongepowered.asm.lib.ClassReader;
@@ -60,7 +60,7 @@ public class ImmersiveEngineeringTransformer implements IClassTransformer {
MixinClassWriter cw = new MixinClassWriter(MixinClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
final byte[] bytes = cw.toByteArray();
AngelicaTweaker.LOGGER.info("[AngelicaCompat]Extra Transformers: Applied ImmersiveEngineeringTransformer");
AngelicaClientTweaker.LOGGER.info("[AngelicaCompat]Extra Transformers: Applied ImmersiveEngineeringTransformer");
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
return bytes;
}
@@ -1,7 +1,7 @@
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.specific;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
import net.minecraft.launchwrapper.IClassTransformer;
import org.spongepowered.asm.lib.ClassReader;
@@ -47,7 +47,7 @@ public class StacksOnStacksTransformer implements IClassTransformer {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
final byte[] bytes = cw.toByteArray();
AngelicaTweaker.LOGGER.info("[AngelicaCompat]Extra Transformers: Applied StacksOnStacksTransformer");
AngelicaClientTweaker.LOGGER.info("[AngelicaCompat]Extra Transformers: Applied StacksOnStacksTransformer");
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
return bytes;
}
@@ -1,6 +1,6 @@
package com.gtnewhorizons.angelica.loading.fml.transformers;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
import com.gtnewhorizons.angelica.loading.shared.transformers.CeleritasBlockTransform;
import net.minecraft.launchwrapper.IClassTransformer;
@@ -14,7 +14,7 @@ public class CeleritasBlockTransformer implements IClassTransformer {
private final String[] exclusions;
public CeleritasBlockTransformer() {
this.inner = new CeleritasBlockTransform(AngelicaTweaker.isObfEnv());
this.inner = new CeleritasBlockTransform(AngelicaClientTweaker.isObfEnv());
this.exclusions = inner.getTransformerExclusions();
this.inner.setCeleritasSetting();
}
@@ -71,6 +71,12 @@ public class AngelicaLateTweaker implements ITweaker {
FMLRelaunchLog.info("[Angelica] Narrowed com.fiskmods.lightsabers.asm transformer exclusion to allow GL redirection");
}
if (narrowEnabled("Ears") && exceptions.remove("com.unascribed.ears")) {
exceptions.add("com.unascribed.ears.asm");
exceptions.add("com.unascribed.ears.common.agent");
FMLRelaunchLog.info("[Angelica] Narrowed com.unascribed.ears transformer exclusion to allow GL redirection");
}
if (narrowEnabled("Alfheim") && exceptions.remove("alfheim.common.core.asm.hook")) {
exceptions.add("alfheim.common.core.asm.hook.AlfheimFieldHookHandler");
exceptions.add("alfheim.common.core.asm.hook.AlfheimHPHooks");
@@ -15,6 +15,7 @@ public class AngelicaRfbPlugin implements RfbPlugin {
@Override
public void onConstruction(@NotNull PluginContext ctx) {
Launch.blackboard.put("angelica.rfbPluginLoaded", Boolean.TRUE);
Launch.classLoader.addClassLoaderExclusion("com.gtnewhorizons.angelica.glsm.redirect.");
}
@Override
@@ -36,7 +36,15 @@ public enum Mixins implements IMixins {
, "angelica.MixinMinecraft"
, "angelica.MixinMinecraft_FrameHook"
, "angelica.MixinMinecraftServer"
, "angelica.bugfixes.MixinItemRenderer_EdgeDepth"
, "angelica.bugfixes.MixinModelCreeper_AuraBodyInflate"
, "angelica.bugfixes.MixinModelWither_ArmorCentering"
, "angelica.bugfixes.MixinRenderBlocks_CrossedSquaresNormal"
, "angelica.bugfixes.MixinRenderCreeper_AuraDepth"
, "angelica.bugfixes.MixinRenderGlobal_DeferredEntityOverlay"
, "angelica.bugfixes.MixinRenderGlobal_DestroyBlock"
, "angelica.bugfixes.MixinRendererLivingEntity_DeferredEntityOverlay"
, "angelica.bugfixes.MixinRenderWither_ArmorCentering"
, "angelica.bugfixes.MixinRendererLivingEntity_EyeDepth"
, "angelica.debug.MixinMinecraft_FPSCap"
, "angelica.ffp.MixinTessellator_CoreProfile"
@@ -248,6 +256,7 @@ public enum Mixins implements IMixins {
, "shaders.MixinRenderEntityFlame"
, "shaders.MixinRendererLivingEntity"
, "shaders.MixinRenderGlobal"
, "shaders.AccessorEntityHorse"
, "shaders.MixinRenderHorse"
, "shaders.MixinRenderItem"
, "shaders.MixinRenderNameTag"
@@ -1,13 +1,16 @@
package com.gtnewhorizons.angelica.proxy;
import biomesoplenty.api.content.BOPCBlocks;
import com.google.common.base.Objects;
import com.gtnewhorizon.gtnhlib.client.model.loading.ModelRegistry;
import com.gtnewhorizon.gtnhlib.client.renderer.vao.VAOManager;
import com.gtnewhorizons.angelica.commands.AngelicaCommand;
import com.gtnewhorizons.angelica.common.BlockError;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.compat.bettercrashes.BetterCrashesCompat;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.config.CompatConfig;
import com.gtnewhorizons.angelica.config.ConfigMigrator;
import com.gtnewhorizons.angelica.debug.F3Direction;
import com.gtnewhorizons.angelica.debug.FrametimeGraph;
import com.gtnewhorizons.angelica.debug.TPSGraph;
@@ -16,7 +19,7 @@ import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.hudcaching.HUDCaching;
import com.gtnewhorizons.angelica.iris.IrisGLSMBridge;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import com.gtnewhorizons.angelica.mixins.interfaces.IGameSettingsExt;
import com.gtnewhorizons.angelica.render.CloudRenderer;
import com.gtnewhorizons.angelica.rendering.AngelicaBlockSafetyRegistry;
@@ -25,6 +28,8 @@ import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasSetup;
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskRegistry;
import com.gtnewhorizons.angelica.rendering.celeritas.threading.DefaultChunkTaskProvider;
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ThreadedChunkTaskProvider;
import com.gtnewhorizons.angelica.utils.AnimationMode;
import com.gtnewhorizons.angelica.utils.ManagedEnum;
import com.gtnewhorizons.angelica.zoom.Zoom;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
@@ -39,17 +44,15 @@ import jss.notfine.core.Settings;
import jss.notfine.gui.GuiCustomMenu;
import jss.notfine.gui.NotFineGameOptionPages;
import me.flashyreese.mods.reeses_sodium_options.client.gui.ReeseSodiumVideoOptionsScreen;
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI;
import net.coderbot.iris.Iris;
import net.coderbot.iris.client.IrisDebugScreenHandler;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiVideoSettings;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.Direction;
@@ -65,29 +68,41 @@ import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
import org.lwjgl.input.Keyboard;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.management.ManagementFactory;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
import static com.gtnewhorizons.angelica.AngelicaMod.MOD_ID;
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
public class ClientProxy extends CommonProxy {
public final class ClientProxy extends CommonProxy {
final Minecraft mc = Minecraft.getMinecraft();
final FrametimeGraph frametimeGraph = new FrametimeGraph();
final TPSGraph tpsGraph = new TPSGraph();
public static BlockError blockError;
public static final ManagedEnum<AnimationMode> animationsMode = new ManagedEnum<>(AnimationMode.VISIBLE_ONLY);
private static final Logger LOGGER = LogManager.getLogger("Angelica");
private static SodiumGameOptions CONFIG;
private final Minecraft mc = Minecraft.getMinecraft();
private final FrametimeGraph frametimeGraph = new FrametimeGraph();
private final TPSGraph tpsGraph = new TPSGraph();
public static Block bopGrass;
public static SodiumGameOptions options() {
if (CONFIG == null) {
CONFIG = SodiumGameOptions.load(ConfigMigrator.handleConfigMigration("angelica-options.json"));
}
return CONFIG;
}
@Override
public void preInit(FMLPreInitializationEvent event) {
ModStatus.preInit();
super.preInit(event);
FMLCommonHandler.instance().bus().register(this);
MinecraftForge.EVENT_BUS.register(this);
ModelRegistry.registerModid(MOD_ID);
blockError = new BlockError();
}
@SubscribeEvent
@@ -138,7 +153,6 @@ public class ClientProxy extends CommonProxy {
FMLCommonHandler.instance().bus().register(this);
MinecraftForge.EVENT_BUS.register(this);
if (ModStatus.isBetterCrashesLoaded) {
BetterCrashesCompat.init();
}
@@ -150,7 +164,7 @@ public class ClientProxy extends CommonProxy {
}
// Register debug commands in dev environment only
if (!AngelicaTweaker.isObfEnv()) {
if (!AngelicaClientTweaker.isObfEnv()) {
ClientCommandHandler.instance.registerCommand(new AngelicaCommand());
}
}
@@ -170,6 +184,9 @@ public class ClientProxy extends CommonProxy {
LOGGER.error("Could not replace LOTR handle render code with thread safe version");
}
}
if(ModStatus.isBOPLoaded) {
bopGrass = BOPCBlocks.newBopGrass;
}
}
float lastIntegratedTickTime;
@@ -10,8 +10,7 @@ import cpw.mods.fml.common.registry.GameRegistry;
public class CommonProxy {
public void preInit(FMLPreInitializationEvent event) {
if (AngelicaConfig.enableTestBlocks){
if (AngelicaConfig.enableTestBlocks) {
GameRegistry.registerBlock(new BlockTest(), "test_block");
}
}
@@ -0,0 +1,215 @@
package com.gtnewhorizons.angelica.rendering;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import lombok.Getter;
import net.coderbot.iris.layer.GbufferPrograms;
import net.coderbot.iris.uniforms.CapturedRenderingState;
import net.coderbot.iris.uniforms.EntityIdHelper;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.minecraft.entity.EntityLivingBase;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* Defers entity overlay rendering (auras, armor effects, etc.) to after all entities have been drawn.
* This lets us fix z-fighting between overlay's own coplanar faces by disabling the depth mask,
* and ensures the overlay composites correctly on top of all opaque geometry.
*
* Used by both the charged creeper aura and the Wither armor overlay.
*
* The deferred render replays shouldRenderPass on the original renderer instance so that any
* mod mixins targeting that method still fire during the deferred pass.
*/
public class DeferredEntityOverlay {
@FunctionalInterface
public interface ShouldRenderPassFn {
int invoke(EntityLivingBase entity, int pass, float partialTick);
}
private static final int INITIAL_CAPACITY = 4;
private static final List<DeferredEntry> deferred = new ArrayList<>(INITIAL_CAPACITY);
private static final List<DeferredEntry> pool = new ArrayList<>(INITIAL_CAPACITY);
private static final FloatBuffer MATRIX_BUF = BufferUtils.createFloatBuffer(16);
// Set by the shouldRenderPass inject, consumed by the doRender WrapOperation.
@Getter
private static boolean overlayPassActive = false;
// Set during deferred flush to prevent re-deferring when shouldRenderPass is replayed.
@Getter
private static boolean replaying = false;
// Pending context from the shouldRenderPass inject, consumed by deferRender.
private static ShouldRenderPassFn pendingShouldRenderPass;
private static RendererLivingEntity pendingRenderer;
private static EntityLivingBase pendingEntity;
private static float pendingPartialTick;
/**
* Called from shouldRenderPass HEAD injects. Marks that the upcoming renderPassModel.render()
* should be deferred. If a previous mark was not consumed (shouldRenderPass returned <= 0,
* so render() was never called).
*/
public static void markOverlayPass(ShouldRenderPassFn shouldRenderPass, RendererLivingEntity renderer,
EntityLivingBase entity, float partialTick) {
overlayPassActive = true;
pendingShouldRenderPass = shouldRenderPass;
pendingRenderer = renderer;
pendingEntity = entity;
pendingPartialTick = partialTick;
}
public static void clearStaleOverlayFlag() {
overlayPassActive = false;
}
/**
* Called from the WrapOperation on renderPassModel.render() in doRender.
* Captures the modelview matrix and animation params, skipping the actual render.
*/
public static void deferRender(float limbSwing, float limbSwingAmount, float ageInTicks,
float headYaw, float headPitch, float scale) {
overlayPassActive = false;
DeferredEntry entry = acquireEntry();
entry.set(pendingShouldRenderPass, pendingRenderer, pendingEntity, pendingPartialTick,
limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch, scale);
MATRIX_BUF.clear();
GLStateManager.glGetFloat(GL11.GL_MODELVIEW_MATRIX, MATRIX_BUF);
MATRIX_BUF.get(entry.matrix);
deferred.add(entry);
pendingShouldRenderPass = null;
pendingRenderer = null;
pendingEntity = null;
}
private static DeferredEntry acquireEntry() {
int size = pool.size();
if (size > 0) {
return pool.remove(size - 1);
}
return new DeferredEntry();
}
private static void recycle() {
for (DeferredEntry entry : deferred) {
entry.shouldRenderPass = null;
entry.renderer = null;
entry.entity = null;
pool.add(entry);
}
deferred.clear();
}
public static void clear() {
recycle();
overlayPassActive = false;
replaying = false;
}
public static void renderAll() {
if (deferred.isEmpty()) return;
GbufferPrograms.beginEntities();
try {
for (DeferredEntry entry : deferred) {
CapturedRenderingState.INSTANCE.setCurrentEntity(EntityIdHelper.getEntityId(entry.entity));
renderOverlay(entry);
}
} finally {
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
GbufferPrograms.endEntities();
}
recycle();
}
private static void renderOverlay(DeferredEntry entry) {
EntityLivingBase entity = entry.entity;
// Restore the entity's lightmap coords
int brightness = entity.getBrightnessForRender(entry.partialTick);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit,
brightness % 65536, (float) brightness / 65536);
// Restore the saved modelview matrix
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
GLStateManager.glPushMatrix();
boolean depthMaskDisabled = false;
try {
MATRIX_BUF.clear();
MATRIX_BUF.put(entry.matrix);
MATRIX_BUF.flip();
GLStateManager.glLoadMatrix(MATRIX_BUF);
// Replay shouldRenderPass pass 1
replaying = true;
int result = entry.shouldRenderPass.invoke(entity, 1, entry.partialTick);
if (result > 0) {
// Disable depth writes so coplanar faces don't z-fight each other
GLStateManager.glDepthMask(false);
depthMaskDisabled = true;
// Disable backface culling so both sides of the overlay shell are visible
GLStateManager.glDisable(GL11.GL_CULL_FACE);
// Render using the model set by shouldRenderPass
entry.renderer.renderPassModel.setLivingAnimations(entity,
entry.limbSwing, entry.limbSwingAmount, entry.partialTick);
entry.renderer.renderPassModel.render(entity,
entry.limbSwing, entry.limbSwingAmount, entry.ageInTicks,
entry.headYaw, entry.headPitch, entry.scale);
}
// Replay shouldRenderPass pass 2
entry.shouldRenderPass.invoke(entity, 2, entry.partialTick);
} finally {
replaying = false;
if (depthMaskDisabled) {
GLStateManager.glDepthMask(true);
GLStateManager.glEnable(GL11.GL_CULL_FACE);
}
GLStateManager.glPopMatrix();
}
}
private static class DeferredEntry {
final float[] matrix = new float[16];
ShouldRenderPassFn shouldRenderPass;
RendererLivingEntity renderer;
EntityLivingBase entity;
float partialTick;
float limbSwing;
float limbSwingAmount;
float ageInTicks;
float headYaw;
float headPitch;
float scale;
void set(ShouldRenderPassFn shouldRenderPass, RendererLivingEntity renderer,
EntityLivingBase entity, float partialTick,
float limbSwing, float limbSwingAmount, float ageInTicks,
float headYaw, float headPitch, float scale) {
this.shouldRenderPass = shouldRenderPass;
this.renderer = renderer;
this.entity = entity;
this.partialTick = partialTick;
this.limbSwing = limbSwing;
this.limbSwingAmount = limbSwingAmount;
this.ageInTicks = ageInTicks;
this.headYaw = headYaw;
this.headPitch = headPitch;
this.scale = scale;
}
}
}
@@ -0,0 +1,31 @@
package com.gtnewhorizons.angelica.rendering;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.model.ModelHorse;
import net.minecraft.client.model.ModelRenderer;
import java.util.ArrayList;
import java.util.List;
/**
* Horse model with all boxes inflated outward, used as a separate armor layer.
* Extends ModelHorse to inherit all animation and render logic. The constructor
* builds the default geometry, then we rebuild every box with inflate applied.
* This mirrors how modern MC uses a separate ModelLayers.HORSE_ARMOR.
*/
public class ModelHorseArmor extends ModelHorse {
public ModelHorseArmor(float inflate) {
super();
for (ModelRenderer renderer : this.boxList) {
List<ModelBox> originalBoxes = new ArrayList<>(renderer.cubeList);
renderer.cubeList.clear();
for (ModelBox box : originalBoxes) {
int width = Math.round(box.posX2 - box.posX1);
int height = Math.round(box.posY2 - box.posY1);
int depth = Math.round(box.posZ2 - box.posZ1);
renderer.addBox(box.posX1, box.posY1, box.posZ1, width, height, depth, inflate);
}
}
}
}
@@ -0,0 +1,5 @@
package com.gtnewhorizons.angelica.rendering;
public class WitherArmorState {
public static boolean pendingInflate = false;
}
@@ -1,11 +1,11 @@
package com.gtnewhorizons.angelica.rendering.celeritas;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.api.ExtQuadLightData;
import com.gtnewhorizons.angelica.api.TintComputer;
import com.gtnewhorizons.angelica.api.TintRegistry;
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
import com.gtnewhorizons.angelica.dynamiclights.IDynamicLightSource;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import com.gtnewhorizons.angelica.rendering.StateAwareTessellator;
import com.gtnewhorizons.angelica.rendering.celeritas.iris.BlockRenderContext;
import com.gtnewhorizons.angelica.rendering.celeritas.iris.IrisExtendedChunkVertexEncoder;
@@ -99,7 +99,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
private Material selectMaterial(Material material, TextureAtlasSprite sprite, boolean isShaderPackOverride) {
// Don't apply transparency-based optimization when shader pack explicitly overrides the material
if (!AngelicaMod.options().performance.useRenderPassOptimization || isShaderPackOverride) {
if (!ClientProxy.options().performance.useRenderPassOptimization || isShaderPackOverride) {
return material;
}
if (sprite != null && sprite.getClass() == TextureAtlasSprite.class && !sprite.hasAnimationMetadata()) {
@@ -129,7 +129,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
final boolean hasDynamicLights = chunkLightSources != null && !chunkLightSources.isEmpty();
final boolean separateAo = BlockRenderingSettings.INSTANCE.shouldUseSeparateAo();
final boolean celeritasSmoothLighting = AngelicaMod.options().quality.useCeleritasSmoothLighting;
final boolean celeritasSmoothLighting = ClientProxy.options().quality.useCeleritasSmoothLighting;
final boolean shaderActive = IrisApi.getInstance().isShaderPackInUse();
final boolean useAoCalculation = lightPipelineReady && (separateAo || celeritasSmoothLighting || shaderActive);
final boolean shouldApplyDiffuse = !BlockRenderingSettings.INSTANCE.shouldDisableDirectionalShading();
@@ -20,6 +20,7 @@ import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.init.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.ReportedException;
import net.minecraft.world.IBlockAccess;
import org.embeddedt.embeddium.impl.render.chunk.RenderSection;
@@ -139,7 +140,20 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
if (block.hasTileEntity(meta)) {
final TileEntity tileEntity = region.getTileEntity(x, y, z);
if (tileEntity != null && TileEntityRendererDispatcher.instance.hasSpecialRenderer(tileEntity)) {
(TileEntityRenderBoundsRegistry.isAlwaysInfiniteExtent(tileEntity) ? renderData.globalBlockEntities : renderData.culledBlockEntities).add(tileEntity);
final boolean isGlobal;
if (TileEntityRenderBoundsRegistry.isAlwaysInfiniteExtent(tileEntity)) {
isGlobal = true;
} else {
final AxisAlignedBB aabb = tileEntity.getRenderBoundingBox();
if (aabb != null) {
final int secMinX = x & ~15, secMinY = y & ~15, secMinZ = z & ~15;
isGlobal = aabb.minX < secMinX || aabb.minY < secMinY || aabb.minZ < secMinZ
|| aabb.maxX > secMinX + 16 || aabb.maxY > secMinY + 16 || aabb.maxZ > secMinZ + 16;
} else {
isGlobal = false;
}
}
(isGlobal ? renderData.globalBlockEntities : renderData.culledBlockEntities).add(tileEntity);
}
}
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.rendering.celeritas;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProvider;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder;
import me.jellysquid.mods.sodium.client.gui.options.named.MultiDrawMode;
@@ -30,7 +31,7 @@ class AngelicaChunkRenderer extends DefaultChunkRenderer {
}
private static MultiDrawEmitter createEmitter() {
MultiDrawMode mode = AngelicaMod.options().advanced.multiDrawMode;
MultiDrawMode mode = ClientProxy.options().advanced.multiDrawMode;
if (mode == MultiDrawMode.INDIRECT) {
boolean supported = GLStateManager.capabilities != null && (GLStateManager.capabilities.OpenGL43 || GLStateManager.capabilities.GL_ARB_multi_draw_indirect);
@@ -1,7 +1,7 @@
package com.gtnewhorizons.angelica.rendering.celeritas;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.mixins.interfaces.RenderSectionManagerAccessor;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder;
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskProvider;
@@ -87,7 +87,7 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
@Override
protected AsyncOcclusionMode getAsyncOcclusionMode() {
return AngelicaMod.options().performance.asyncOcclusionMode;
return ClientProxy.options().performance.asyncOcclusionMode;
}
@Override
@@ -97,7 +97,7 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
@Override
protected boolean useFogOcclusion() {
return AngelicaMod.options().performance.useFogOcclusion && !IrisShaderProviderHolder.isActive();
return ClientProxy.options().performance.useFogOcclusion && !IrisShaderProviderHolder.isActive();
}
@Override
@@ -113,7 +113,7 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
return false;
}
}
return AngelicaMod.options().performance.useOcclusionCulling;
return ClientProxy.options().performance.useOcclusionCulling;
}
@Override
@@ -152,7 +152,7 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
@Override
protected boolean allowImportantRebuilds() {
return !AngelicaMod.options().performance.alwaysDeferChunkUpdates;
return !ClientProxy.options().performance.alwaysDeferChunkUpdates;
}
@Override
@@ -2,9 +2,9 @@ package com.gtnewhorizons.angelica.rendering.celeritas;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import org.embeddedt.embeddium.impl.gl.device.GLRenderDevice;
import org.lwjgl.opengl.GL15;
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
public class CeleritasSetup {
private static boolean initialized = false;
@@ -12,7 +12,7 @@ public class CeleritasSetup {
public static void ensureInitialized() {
if (!initialized && AngelicaConfig.enableCeleritas) {
GLRenderDevice.VANILLA_STATE_RESETTER = () -> GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
LOGGER.debug("Celeritas init");
AngelicaClientTweaker.LOGGER.debug("Celeritas init");
initialized = true;
}
}
@@ -1,10 +1,10 @@
package com.gtnewhorizons.angelica.rendering.celeritas;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
import com.gtnewhorizons.angelica.dynamiclights.IDynamicLightWorldRenderer;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.ITileEntityBoundingBoxCache;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import com.gtnewhorizons.angelica.rendering.TileEntityRenderBoundsRegistry;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProvider;
@@ -127,7 +127,7 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
}
}
if (AngelicaMod.options().performance.useCompactVertexFormat) {
if (ClientProxy.options().performance.useCompactVertexFormat) {
return ChunkMeshFormats.COMPACT;
}
return ChunkMeshFormats.VANILLA_LIKE;
@@ -155,7 +155,7 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
renderSectionManager.setCameraPosition(transform.x, transform.y, transform.z);
this.useEntityCulling = AngelicaMod.options().performance.useEntityCulling;
this.useEntityCulling = ClientProxy.options().performance.useEntityCulling;
super.setupTerrain(viewport, cameraState, frame, spectator, updateChunksImmediately);
@@ -313,7 +313,7 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
public int renderBlockEntities(float partialTicks) {
final int pass = MinecraftForgeClient.getRenderPass();
teRenderContext.set(partialTicks, pass);
if (pass == 0 || !AngelicaMod.options().performance.translucencySorting) {
if (pass == 0 || !ClientProxy.options().performance.translucencySorting) {
return super.renderBlockEntities(teRenderContext);
}
int count = 0;
@@ -56,16 +56,19 @@ final class Enchantment extends OverrideBase {
GLStateManager.glEnable(GL11.GL_ALPHA_TEST);
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.01f);
GLStateManager.glEnable(GL11.GL_BLEND);
GLStateManager.glDepthFunc(GL11.GL_EQUAL);
lightingWasEnabled = GLStateManager.glGetBoolean(GL11.GL_LIGHTING);
GLStateManager.glDisable(GL11.GL_LIGHTING);
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
}
static void endOuter3D() {
GLStateManager.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
GLStateManager.glDisable(GL11.GL_BLEND);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glDepthMask(true);
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
if (lightingWasEnabled) {
GLStateManager.glEnable(GL11.GL_LIGHTING);
}
@@ -139,6 +142,17 @@ final class Enchantment extends OverrideBase {
return;
}
begin(intensity);
// Depth pre-pass
GLStateManager.glColorMask(false, false, false, false);
GLStateManager.glDepthMask(true);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
ItemRenderer.renderItemIn2D(Tessellator.instance, 1.0f, 0.0f, 0.0f, 1.0f, width, height, ITEM_2D_THICKNESS);
// Color pass
GLStateManager.glColorMask(true, true, true, true);
GLStateManager.glDepthMask(false);
GLStateManager.glDepthFunc(GL11.GL_EQUAL);
ItemRenderer.renderItemIn2D(Tessellator.instance, 1.0f, 0.0f, 0.0f, 1.0f, width, height, ITEM_2D_THICKNESS);
end();
}
+2 -2
View File
@@ -2,7 +2,7 @@ package jss.notfine.asm;
import java.util.Objects;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FrameNode;
@@ -133,7 +133,7 @@ public class ASMUtils {
yield false;
}
default -> {
AngelicaTweaker.LOGGER.warn("Unchecked node found: " + node1.getClass());
AngelicaClientTweaker.LOGGER.warn("Unchecked node found: " + node1.getClass());
yield node1.toString()
.equals(node2.toString());
}
@@ -1,10 +1,10 @@
package jss.notfine.asm.mappings;
import java.util.ArrayList;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import net.minecraft.launchwrapper.Launch;
import java.util.ArrayList;
/**
* This class und inherited classes are adapted from
* <a href=
@@ -48,7 +48,7 @@ public class Namer {
public static void initNames() {
final boolean obfuscated = !(Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
AngelicaTweaker.LOGGER.info("Environment obfuscated: {}", obfuscated);
AngelicaClientTweaker.LOGGER.info("Environment obfuscated: {}", obfuscated);
if (obfuscated) {
new NamerObf().setNames();
} else {
@@ -1,16 +1,16 @@
package jss.notfine.asm.mappings;
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
import jss.notfine.asm.mappings.Names.Clas;
import jss.notfine.asm.mappings.Names.Fiel;
import jss.notfine.asm.mappings.Names.Meth;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import jss.notfine.asm.mappings.Names.Clas;
import jss.notfine.asm.mappings.Names.Fiel;
import jss.notfine.asm.mappings.Names.Meth;
public class NamerMcp extends NamerSrg {
@Override
@@ -71,15 +71,15 @@ public class NamerMcp extends NamerSrg {
nameMap = loadReobfMap(confPath + "packaged.srg");
for (Clas c : ac) {
String s = nameMap.get(c.name);
AngelicaTweaker.LOGGER.trace("C {} {}", c.name, s);
AngelicaClientTweaker.LOGGER.trace("C {} {}", c.name, s);
}
for (Fiel f : af) {
String s = nameMap.get(f.clas + "/" + f.name);
AngelicaTweaker.LOGGER.trace("F {} {}", f.name, s);
AngelicaClientTweaker.LOGGER.trace("F {} {}", f.name, s);
}
for (Meth m : am) {
String s = nameMap.get(m.clas + "/" + m.name + m.desc);
AngelicaTweaker.LOGGER.trace("M {} {}", m.name, s);
AngelicaClientTweaker.LOGGER.trace("M {} {}", m.name, s);
}
}
@@ -1,6 +1,7 @@
package me.jellysquid.mods.sodium.client.gui.options.storage;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
import java.io.IOException;
@@ -9,7 +10,7 @@ public class SodiumOptionsStorage implements OptionStorage<SodiumGameOptions> {
private final SodiumGameOptions options;
public SodiumOptionsStorage() {
this.options = AngelicaMod.options();
this.options = ClientProxy.options();
}
@Override
+50 -15
View File
@@ -3,30 +3,30 @@ package net.coderbot.iris;
import com.google.common.base.Throwables;
import com.gtnewhorizon.gtnhlib.client.renderer.CapturingTessellator;
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.Tags;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.InputEvent;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import lombok.Getter;
import net.coderbot.iris.block_context.BlockContextHolder;
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import net.coderbot.iris.celeritas.IrisCeleritasShaderProvider;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.config.IrisConfig;
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
import net.coderbot.iris.gl.shader.StandardMacros;
import net.coderbot.iris.gui.screen.ShaderPackScreen;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.transform.ShaderTransformer;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline;
import net.coderbot.iris.pipeline.PipelineManager;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
import net.coderbot.iris.pipeline.transform.ShaderTransformer;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.shaderpack.OptionalBoolean;
import net.coderbot.iris.shaderpack.ProgramSet;
import net.coderbot.iris.shaderpack.ShaderPack;
@@ -35,7 +35,6 @@ import net.coderbot.iris.shaderpack.option.OptionSet;
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.block_context.BlockContextHolder;
import net.coderbot.iris.texture.pbr.PBRTextureManager;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
@@ -64,7 +63,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -72,6 +70,7 @@ import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.zip.ZipError;
@@ -113,11 +112,31 @@ public class Iris {
// Used in favor of queueDefaultShaderPackOptionValues() for resetting as the
// behavior is more concrete and therefore is more likely to repair a user's issues
private static boolean resetShaderPackOptions = false;
private static boolean loadShaderPackWhenPossible = false;
private static String IRIS_VERSION;
@Getter
private static boolean fallback;
public static boolean loadedIncompatiblePack() {
return DHCompat.lastPackIncompatible();
}
public static void loadShaderpackWhenPossible() {
loadShaderPackWhenPossible = true;
}
public static void tryLoadShaderpackWhenPossible() {
if (loadShaderPackWhenPossible) {
loadShaderPackWhenPossible = false;
try {
reload();
} catch (IOException e) {
logger.error("Error during deferred shader reload", e);
}
}
}
/**
* Lazy executor for parallelizing shader transformations during shader pack loading.
* Creates threads on demand and shuts down after a period of inactivity.
@@ -335,7 +354,7 @@ public class Iris {
final boolean released = !Keyboard.getEventKeyState();
if (Minecraft.getMinecraft().gameSettings.showDebugInfo && GuiScreen.isShiftKeyDown() && GuiScreen.isCtrlKeyDown() && released) {
if (key == Keyboard.KEY_N) {
AngelicaMod.animationsMode.next();
ClientProxy.animationsMode.next();
}
}
}
@@ -350,6 +369,7 @@ public class Iris {
* <p>This is called right before options are loaded, so we can add key bindings here.</p>
*/
public void onEarlyInitialize() {
DHCompat.run();
try {
if (!Files.exists(getShaderpacksDirectory())) {
Files.createDirectories(getShaderpacksDirectory());
@@ -395,8 +415,19 @@ public class Iris {
PBRTextureManager.INSTANCE.init();
// Only load the shader pack when we can access OpenGL
loadShaderpack();
boolean isDHLoaded;
try {
Class.forName("com.seibel.distanthorizons.DistantHorizonsTweaker");
isDHLoaded = true;
}
catch (Exception e) {
isDHLoaded = false;
}
// When DH is present, defer shaderpack loading until its init callback has run.
if (!isDHLoaded) {
loadShaderpack();
}
}
/**
@@ -448,11 +479,9 @@ public class Iris {
// Attempt to load an external shaderpack if it is available
final Optional<String> externalName = irisConfig.getShaderPackName();
if (!externalName.isPresent()) {
if (externalName.isEmpty()) {
logger.info("Shaders are disabled because no valid shaderpack is selected");
setShadersDisabled();
return;
}
@@ -721,6 +750,12 @@ public class Iris {
BlockRenderingSettings.INSTANCE.reloadRendererIfRequired();
}
if (loadedIncompatiblePack() && Minecraft.getMinecraft().thePlayer != null) {
Iris.logger.warn("Incompatible pack for DH!");
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.BOLD.toString() + EnumChatFormatting.RED + "This pack doesn't have DH support."));
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "Distant Horizons (DH) chunks won't show up. This isn't a bug, get another shader."));
}
}
/**
@@ -1,7 +1,7 @@
package net.coderbot.iris.client;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.proxy.ClientProxy;
import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.coderbot.iris.Iris;
@@ -47,7 +47,7 @@ public class IrisDebugScreenHandler {
event.right.add("[" + Iris.MODNAME + "] Shaders are disabled");
}
if (AngelicaConfig.speedupAnimations) {
event.right.add(Math.min(event.right.size(), 9), "animationsMode: " + AngelicaMod.animationsMode);
event.right.add(Math.min(event.right.size(), 9), "animationsMode: " + ClientProxy.animationsMode);
}
Iris.getPipelineManager().getPipeline().ifPresent(pipeline -> pipeline.addDebugText(event.left));
@@ -1,14 +1,129 @@
package net.coderbot.iris.compat.dh;
/**
* Stub implementation of Distant Horizons compatibility.
*/
public class DHCompat {
public int getDepthTex() {
return 0;
}
import com.gtnewhorizons.angelica.rendering.RenderingState;
import net.coderbot.iris.Iris;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.minecraft.client.Minecraft;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
public int getDepthTexNoTranslucent() {
return 0;
}
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
public class DHCompat {
private static boolean dhPresent;
private static boolean lastIncompatible;
private DHCompatInternal compatInternalInstance;
private final static Matrix4f tempProj = new Matrix4f();
public DHCompat(DeferredWorldRenderingPipeline pipeline, boolean renderDHShadow) {
if (pipeline == null) {
return;
}
try {
if (dhPresent) {
compatInternalInstance = new DHCompatInternal(pipeline, renderDHShadow);
lastIncompatible = compatInternalInstance.incompatiblePack();
}
} catch (Throwable e) {
lastIncompatible = false;
if (e instanceof InvocationTargetException ite) {
throw new RuntimeException("Unknown error loading Distant Horizons compatibility.", ite.getCause());
} else {
throw new RuntimeException("Unknown error loading Distant Horizons compatibility.", e);
}
}
}
public static Matrix4fc getProjection() {
Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();
if (!dhPresent) {
return projection;
}
return tempProj.setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), DHCompat.getNearPlane(), DHCompat.getFarPlane());
}
public static void run() {
try {
Class.forName("com.seibel.distanthorizons.DistantHorizonsTweaker");
dhPresent = true;
}
catch (Exception e) {
dhPresent = false;
}
try {
if (dhPresent) {
LodRendererEvents.setupEventHandlers();
}
} catch (Throwable e) {
dhPresent = false;
if (e instanceof ExceptionInInitializerError eiie) {
throw new RuntimeException("Failure loading DH compat.", eiie.getCause());
} else {
throw new RuntimeException("DH found, but one or more API methods are missing. Iris requires DH [2.0.4] or DH API version [1.1.0] or newer. Please make sure you are on the latest version of DH and Iris.", e);
}
}
}
public static boolean lastPackIncompatible() {
return dhPresent && hasRenderingEnabled() && lastIncompatible;
}
public static float getFarPlane() {
if (!dhPresent) return 0.01f;
return DHCompatInternal.getFarPlane();
}
public static float getNearPlane() {
if (!dhPresent) return 0.01f;
return DHCompatInternal.getNearPlane();
}
public static int getRenderDistance() {
if (!dhPresent) return Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16;
return DHCompatInternal.getRenderDistance();
}
public static boolean checkFrame() {
if (!dhPresent) {
return false;
}
return DHCompatInternal.checkFrame();
}
public static boolean hasRenderingEnabled() {
if (!dhPresent) {
return false;
}
return checkFrame();
}
public void clearPipeline() {
if (compatInternalInstance == null) return;
compatInternalInstance.clear();
}
public int getDepthTex() {
if (compatInternalInstance == null) return -1;
return compatInternalInstance.getStoredDepthTex();
}
public int getDepthTexNoTranslucent() {
if (compatInternalInstance == null) return -1;
return compatInternalInstance.getDepthTexNoTranslucent();
}
public DHCompatInternal getInstance() {
return compatInternalInstance;
}
}
@@ -0,0 +1,291 @@
package net.coderbot.iris.compat.dh;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import net.coderbot.iris.Iris;
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
import net.coderbot.iris.gl.texture.DepthBufferFormat;
import net.coderbot.iris.gl.texture.DepthCopyStrategy;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.rendertarget.DepthTexture;
import net.coderbot.iris.rendertarget.IRenderTargetExt;
import net.coderbot.iris.shaderpack.CloudSetting;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CapturedRenderingState;
import net.irisshaders.iris.api.v0.IrisApi;
import net.minecraft.client.Minecraft;
import org.lwjgl.opengl.GL11;
import java.io.IOException;
public class DHCompatInternal {
public static final DHCompatInternal SHADERLESS = new DHCompatInternal(null, false);
static boolean dhEnabled;
private static int guiScale = -1;
private final DeferredWorldRenderingPipeline pipeline;
public boolean shouldOverrideShadow;
public boolean shouldOverride;
private GlFramebuffer dhGenericFramebuffer;
private IrisLodRenderProgram solidProgram;
private IrisGenericRenderProgram genericShader;
private IrisLodRenderProgram translucentProgram;
private IrisLodRenderProgram shadowProgram;
private GlFramebuffer dhTerrainFramebuffer;
private DhFrameBufferWrapper dhTerrainFramebufferWrapper;
private GlFramebuffer dhWaterFramebuffer;
private GlFramebuffer dhShadowFramebuffer;
private DhFrameBufferWrapper dhShadowFramebufferWrapper;
private DepthTexture depthTexNoTranslucent;
private boolean translucentDepthDirty;
private int storedDepthTex = -1;
private boolean incompatible = false;
private int cachedVersion;
public DHCompatInternal(DeferredWorldRenderingPipeline pipeline, boolean dhShadowEnabled) {
this.pipeline = pipeline;
if (pipeline == null || !DhApi.Delayed.configs.graphics().renderingEnabled().getValue()) {
return;
}
if (pipeline.getDHTerrainShader().isEmpty() && pipeline.getDHWaterShader().isEmpty()) {
Iris.logger.warn("No DH shader found in this pack.");
incompatible = true;
return;
}
cachedVersion = ((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion();
createDepthTex(Minecraft.getMinecraft().getFramebuffer().framebufferWidth, Minecraft.getMinecraft().getFramebuffer().framebufferHeight);
translucentDepthDirty = true;
ProgramSource terrain = pipeline.getDHTerrainShader().get();
solidProgram = IrisLodRenderProgram.createProgram(terrain.getName(), false, false, terrain, pipeline.getCustomUniforms(), pipeline);
ProgramSource generic = pipeline.getDHGenericShader().get();
genericShader = IrisGenericRenderProgram.createProgram(generic.getName() + "_g", false, false, generic, pipeline.getCustomUniforms(), pipeline);
dhGenericFramebuffer = pipeline.createDHFramebuffer(generic, false);
if (pipeline.getDHWaterShader().isPresent()) {
ProgramSource water = pipeline.getDHWaterShader().get();
translucentProgram = IrisLodRenderProgram.createProgram(water.getName(), false, true, water, pipeline.getCustomUniforms(), pipeline);
dhWaterFramebuffer = pipeline.createDHFramebuffer(water, true);
}
if (pipeline.getDHShadowShader().isPresent() && dhShadowEnabled) {
ProgramSource shadow = pipeline.getDHShadowShader().get();
shadowProgram = IrisLodRenderProgram.createProgram(shadow.getName(), true, false, shadow, pipeline.getCustomUniforms(), pipeline);
if (pipeline.hasShadowRenderTargets()) {
dhShadowFramebuffer = pipeline.createDHFramebufferShadow(shadow);
dhShadowFramebufferWrapper = new DhFrameBufferWrapper(dhShadowFramebuffer);
}
shouldOverrideShadow = true;
} else {
shouldOverrideShadow = false;
}
dhTerrainFramebuffer = pipeline.createDHFramebuffer(terrain, false);
dhTerrainFramebufferWrapper = new DhFrameBufferWrapper(dhTerrainFramebuffer);
if (translucentProgram == null) {
translucentProgram = solidProgram;
}
shouldOverride = true;
}
public static int getDhBlockRenderDistance() {
if (DhApi.Delayed.configs == null || !dhEnabled) {
// Called before DH has finished setup
return Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16;
}
return DhApi.Delayed.configs.graphics().chunkRenderDistance().getValue() * 16;
}
public static int getRenderDistance() {
return getDhBlockRenderDistance();
}
public static float getFarPlane() {
if (DhApi.Delayed.configs == null) {
// Called before DH has finished setup
return 0;
}
int lodChunkDist = DhApi.Delayed.configs.graphics().chunkRenderDistance().getValue();
int lodBlockDist = lodChunkDist * 16;
// sqrt 2 to prevent the corners from being cut off
return (float) ((lodBlockDist + 512) * Math.sqrt(2));
}
public static float getNearPlane() {
if (DhApi.Delayed.renderProxy == null) {
// Called before DH has finished setup
return 0;
}
return DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(CapturedRenderingState.INSTANCE.getTickDelta());
}
public static boolean checkFrame() {
if (guiScale == -1) {
guiScale = Minecraft.getMinecraft().gameSettings.guiScale;
}
if (DhApi.Delayed.configs == null) return dhEnabled;
if ((dhEnabled != DhApi.Delayed.configs.graphics().renderingEnabled().getValue() || guiScale != Minecraft.getMinecraft().gameSettings.guiScale)
&& IrisApi.getInstance().isShaderPackInUse()) {
guiScale = Minecraft.getMinecraft().gameSettings.guiScale;
dhEnabled = DhApi.Delayed.configs.graphics().renderingEnabled().getValue();
try {
Iris.reload();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return dhEnabled;
}
public boolean incompatiblePack() {
return incompatible;
}
public void reconnectDHTextures(int depthTex) {
if (((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion() != cachedVersion) {
cachedVersion = ((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion();
createDepthTex(Minecraft.getMinecraft().getFramebuffer().framebufferWidth, Minecraft.getMinecraft().getFramebuffer().framebufferHeight);
}
if (storedDepthTex != depthTex && dhTerrainFramebuffer != null) {
storedDepthTex = depthTex;
dhTerrainFramebuffer.addDepthAttachmentBypass(depthTex);
if (dhWaterFramebuffer != null) {
dhWaterFramebuffer.addDepthAttachmentBypass(depthTex);
}
if (dhGenericFramebuffer != null) {
dhGenericFramebuffer.addDepthAttachmentBypass(depthTex);
}
}
}
public void createDepthTex(int width, int height) {
if (depthTexNoTranslucent != null) {
depthTexNoTranslucent.destroy();
depthTexNoTranslucent = null;
}
translucentDepthDirty = true;
depthTexNoTranslucent = new DepthTexture(width, height, DepthBufferFormat.DEPTH32F);
}
public void clear() {
if (solidProgram != null) {
solidProgram.free();
solidProgram = null;
}
if (translucentProgram != null) {
translucentProgram.free();
translucentProgram = null;
}
if (shadowProgram != null) {
shadowProgram.free();
shadowProgram = null;
}
shouldOverrideShadow = false;
shouldOverride = false;
dhTerrainFramebuffer = null;
dhWaterFramebuffer = null;
dhShadowFramebuffer = null;
storedDepthTex = -1;
translucentDepthDirty = true;
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, dhTerrainFramebufferWrapper);
OverrideInjector.INSTANCE.unbind(IDhApiGenericObjectShaderProgram.class, genericShader);
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, dhShadowFramebufferWrapper);
dhTerrainFramebufferWrapper = null;
dhShadowFramebufferWrapper = null;
}
public void setModelPos(DhApiVec3f modelPos) {
solidProgram.bind();
solidProgram.setModelPos(modelPos);
translucentProgram.bind();
translucentProgram.setModelPos(modelPos);
solidProgram.bind();
}
public IrisLodRenderProgram getSolidShader() {
return solidProgram;
}
public GlFramebuffer getSolidFB() {
return dhTerrainFramebuffer;
}
public DhFrameBufferWrapper getSolidFBWrapper() {
return dhTerrainFramebufferWrapper;
}
public IrisLodRenderProgram getShadowShader() {
return shadowProgram;
}
public GlFramebuffer getShadowFB() {
return dhShadowFramebuffer;
}
public DhFrameBufferWrapper getShadowFBWrapper() {
return dhShadowFramebufferWrapper;
}
public IrisLodRenderProgram getTranslucentShader() {
if (translucentProgram == null) {
return solidProgram;
}
return translucentProgram;
}
public int getStoredDepthTex() {
return storedDepthTex;
}
public void copyTranslucents(int width, int height) {
if (translucentDepthDirty) {
translucentDepthDirty = false;
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, depthTexNoTranslucent.getTextureId());
dhTerrainFramebuffer.bindAsReadBuffer();
GLStateManager.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, DepthBufferFormat.DEPTH32F.getGlInternalFormat(), 0, 0, width, height, 0);
} else {
DepthCopyStrategy.fastest(false).copy(dhTerrainFramebuffer, storedDepthTex, null, depthTexNoTranslucent.getTextureId(), width, height);
}
}
public GlFramebuffer getTranslucentFB() {
return dhWaterFramebuffer;
}
public GlFramebuffer getGenericFB() {
return dhGenericFramebuffer;
}
public int getDepthTexNoTranslucent() {
if (depthTexNoTranslucent == null) return 0;
return depthTexNoTranslucent.getTextureId();
}
public IDhApiGenericObjectShaderProgram getGenericShader() {
return genericShader;
}
public boolean avoidRenderingClouds() {
return pipeline != null && (pipeline.getDHCloudSetting() == CloudSetting.OFF || (pipeline.getDHCloudSetting() == CloudSetting.DEFAULT && pipeline.getCloudSetting() == CloudSetting.OFF));
}
}
@@ -0,0 +1,55 @@
package net.coderbot.iris.compat.dh;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
import org.lwjgl.opengl.GL30;
public class DhFrameBufferWrapper implements IDhApiFramebuffer {
private final GlFramebuffer framebuffer;
public DhFrameBufferWrapper(GlFramebuffer framebuffer) {
this.framebuffer = framebuffer;
}
@Override
public boolean overrideThisFrame() {
return true;
}
@Override
public void bind() {
this.framebuffer.bind();
}
@Override
public void addDepthAttachment(int i, boolean b) {
// ignore
}
@Override
public int getId() {
return this.framebuffer.getId();
}
@Override
public int getStatus() {
this.bind();
int status = GLStateManager.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER);
return status;
}
@Override
public void addColorAttachment(int i, int i1) {
// ignore
}
@Override
public void destroy() {
// ignore
//this.framebuffer.destroy();
}
}
@@ -0,0 +1,351 @@
package net.coderbot.iris.compat.dh;
import com.google.common.primitives.Ints;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import com.mitchej123.lwjgl.MemoryStack;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import net.coderbot.iris.gl.blending.BufferBlendOverride;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.program.ProgramUniforms;
import net.coderbot.iris.gl.shader.GlShader;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
import net.coderbot.iris.pipeline.transform.PatchShaderType;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CommonUniforms;
import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
import net.irisshaders.iris.api.v0.IrisApi;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class IrisGenericRenderProgram implements IDhApiGenericObjectShaderProgram {
// Uniforms
public final int modelViewUniform;
public final int modelViewInverseUniform;
public final int projectionUniform;
public final int projectionInverseUniform;
public final int normalMatrix3fUniform;
// Fog/Clip Uniforms
private final int id;
private final ProgramUniforms uniforms;
private final CustomUniforms customUniforms;
private final ProgramSamplers samplers;
private final ProgramImages images;
private final BlendModeOverride blend;
private final BufferBlendOverride[] bufferBlendOverrides;
private final Matrix4f tempModel = new Matrix4f();
private final Matrix4f tempProj = new Matrix4f();
private final Matrix4f tempMat4 = new Matrix4f();
private final Matrix3f tempMat3 = new Matrix3f();
private final int instancedShaderOffsetChunkUniform;
private final int instancedShaderOffsetSubChunkUniform;
private final int instancedShaderCameraChunkPosUniform;
private final int instancedShaderCameraSubChunkPosUniform;
private final int instancedShaderProjectionModelViewMatrixUniform;
private final int va;
private final int uBlockLight;
private final int uSkyLight;
// This will bind AbstractVertexAttribute
private IrisGenericRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) {
id = GLStateManager.glCreateProgram();
GLStateManager.glBindAttribLocation(this.id, 0, "vPosition");
this.bufferBlendOverrides = bufferBlendOverrides;
GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex);
GLStateManager.glAttachShader(id, vert.getHandle());
GlShader tessCont = null;
if (tessControl != null) {
tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl);
GLStateManager.glAttachShader(id, tessCont.getHandle());
}
GlShader tessE = null;
if (tessEval != null) {
tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval);
GLStateManager.glAttachShader(id, tessE.getHandle());
}
GlShader geom = null;
if (geometry != null) {
geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry);
GLStateManager.glAttachShader(id, geom.getHandle());
}
GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment);
GLStateManager.glAttachShader(id, frag.getHandle());
GLStateManager.glLinkProgram(this.id);
int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
if (status != 1) {
String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999);
this.free();
throw new RuntimeException(message);
} else {
GLStateManager.glUseProgram(this.id);
}
vert.destroy();
frag.destroy();
if (tessCont != null) tessCont.destroy();
if (tessE != null) tessE.destroy();
if (geom != null) geom.destroy();
blend = override;
ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id);
ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX);
customUniforms.assignTo(uniformBuilder);
BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder);
ProgramImages.Builder builder = ProgramImages.builder(id);
pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder,
isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(),
isShadowPass, true, true, false);
customUniforms.mapholderToPass(uniformBuilder, this);
this.uniforms = uniformBuilder.buildUniforms();
this.customUniforms = customUniforms;
samplers = samplerBuilder.build();
images = builder.build();
this.va = GLStateManager.glGenVertexArrays();
GLStateManager.glBindVertexArray(va);
GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GLStateManager.glEnableVertexAttribArray(0);
projectionUniform = tryGetUniformLocation2("iris_ProjectionMatrix");
projectionInverseUniform = tryGetUniformLocation2("iris_ProjectionMatrixInverse");
modelViewUniform = tryGetUniformLocation2("iris_ModelViewMatrix");
modelViewInverseUniform = tryGetUniformLocation2("iris_ModelViewMatrixInverse");
normalMatrix3fUniform = tryGetUniformLocation2("iris_NormalMatrix");
this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation2("uOffsetChunk");
this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation2("uOffsetSubChunk");
this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation2("uCameraPosChunk");
this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation2("uCameraPosSubChunk");
this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation2("uProjectionMvm");
this.uBlockLight = this.tryGetUniformLocation2("uBlockLight");
this.uSkyLight = this.tryGetUniformLocation2("uSkyLight");
}
public static IrisGenericRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) {
Map<PatchShaderType, String> transformed = TransformPatcher.patchDHGeneric(
name,
source.getVertexSource().orElseThrow(RuntimeException::new),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getGeometrySource().orElse(null),
source.getFragmentSource().orElseThrow(RuntimeException::new),
pipeline.getTextureMap());
String vertex = transformed.get(PatchShaderType.VERTEX);
String tessControl = transformed.get(PatchShaderType.TESS_CONTROL);
String tessEval = transformed.get(PatchShaderType.TESS_EVAL);
String geometry = transformed.get(PatchShaderType.GEOMETRY);
String fragment = transformed.get(PatchShaderType.FRAGMENT);
PatchedShaderPrinter.debugPatchedShaders(source.getName() + "_g", vertex, geometry, tessControl, tessEval, fragment);
List<BufferBlendOverride> bufferOverrides = new ArrayList<>();
source.getDirectives().getBufferBlendOverrides().forEach(information -> {
int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex());
if (index > -1) {
bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode()));
}
});
return new IrisGenericRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline);
}
// Noise Uniforms
private static int getChunkPosFromDouble(double value) {
return (int) Math.floor(value / 16);
}
private static float getSubChunkPosFromDouble(double value) {
double chunkPos = Math.floor(value / 16);
return (float) (value - chunkPos * 16);
}
public int tryGetUniformLocation2(CharSequence name) {
return GLStateManager.glGetUniformLocation(this.id, name);
}
public void setUniform(int index, Matrix4f matrix) {
if (index == -1 || matrix == null) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(16);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix4(index, false, buffer);
}
}
public void setUniform(int index, Matrix3f matrix) {
if (index == -1) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(9);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix3(index, false, buffer);
}
}
// Override ShaderProgram.bind()
public void bind(DhApiRenderParam renderParam) {
GLStateManager.glBindVertexArray(va);
GLStateManager.glUseProgram(id);
if (blend != null) blend.apply();
for (BufferBlendOverride override : bufferBlendOverrides) {
override.apply();
}
toJOML(tempModel, renderParam.dhModelViewMatrix);
toJOML(tempProj, renderParam.dhProjectionMatrix);
setUniform(modelViewUniform, tempModel);
setUniform(projectionUniform, tempProj);
this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, tempMat4.set(tempProj).mul(tempModel));
tempModel.invert();
tempProj.invert();
setUniform(modelViewInverseUniform, tempModel);
setUniform(projectionInverseUniform, tempProj);
setUniform(normalMatrix3fUniform, tempModel.transpose3x3(tempMat3));
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT);
DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture();
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId());
samplers.update();
uniforms.update();
customUniforms.push(this);
images.update();
}
public void unbind() {
GLStateManager.glBindVertexArray(0);
GLStateManager.glUseProgram(0);
ProgramUniforms.clearActiveUniforms();
ProgramSamplers.clearActiveSamplers();
BlendModeOverride.restore();
}
@Override
public void bindVertexBuffer(int i) {
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, i);
GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 12, 0);
}
@Override
public boolean overrideThisFrame() {
return IrisApi.getInstance().isShaderPackInUse();
}
@Override
public int getId() {
return id;
}
public void free() {
GLStateManager.glDeleteProgram(id);
}
public void fillIndirectUniformData(DhApiRenderParam dhApiRenderParam, DhApiRenderableBoxGroupShading dhApiRenderableBoxGroupShading, IDhApiRenderableBoxGroup boxGroup, DhApiVec3d camPos) {
bind(dhApiRenderParam);
GLStateManager.enableDepthTest();
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
this.setUniform(this.instancedShaderOffsetChunkUniform,
getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
);
this.setUniform(this.instancedShaderOffsetSubChunkUniform,
getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
);
this.setUniform(this.instancedShaderCameraChunkPosUniform,
getChunkPosFromDouble(camPos.x),
getChunkPosFromDouble(camPos.y),
getChunkPosFromDouble(camPos.z)
);
this.setUniform(this.instancedShaderCameraSubChunkPosUniform,
getSubChunkPosFromDouble(camPos.x),
getSubChunkPosFromDouble(camPos.y),
getSubChunkPosFromDouble(camPos.z)
);
this.setUniform(this.uBlockLight,
boxGroup.getBlockLight());
this.setUniform(this.uSkyLight,
boxGroup.getSkyLight());
}
@Override
public void fillSharedDirectUniformData(DhApiRenderParam dhApiRenderParam, DhApiRenderableBoxGroupShading dhApiRenderableBoxGroupShading, IDhApiRenderableBoxGroup iDhApiRenderableBoxGroup, DhApiVec3d dhApiVec3d) {
throw new IllegalStateException("Only indirect is supported with Iris.");
}
@Override
public void fillDirectUniformData(DhApiRenderParam dhApiRenderParam, IDhApiRenderableBoxGroup iDhApiRenderableBoxGroup, DhApiRenderableBox dhApiRenderableBox, DhApiVec3d dhApiVec3d) {
throw new IllegalStateException("Only indirect is supported with Iris.");
}
private void toJOML(Matrix4f target, DhApiMat4f mat4f) {
target.setTransposed(mat4f.getValuesAsArray());
}
private void setUniform(int index, int value) {
GLStateManager.glUniform1i(index, value);
}
private void setUniform(int index, float value) {
GLStateManager.glUniform1f(index, value);
}
private void setUniform(int index, float x, float y, float z) {
GLStateManager.glUniform3f(index, x, y, z);
}
private void setUniform(int index, int x, int y, int z) {
GLStateManager.glUniform3i(index, x, y, z);
}
}
@@ -0,0 +1,266 @@
package net.coderbot.iris.compat.dh;
import com.google.common.primitives.Ints;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import com.mitchej123.lwjgl.MemoryStack;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import net.coderbot.iris.gl.blending.BufferBlendOverride;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.program.ProgramUniforms;
import net.coderbot.iris.gl.shader.GlShader;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.gl.texture.TextureType;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
import net.coderbot.iris.pipeline.transform.PatchShaderType;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CommonUniforms;
import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL32;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class IrisLodRenderProgram {
// Uniforms
public final int modelOffsetUniform;
public final int worldYOffsetUniform;
public final int mircoOffsetUniform;
public final int modelViewUniform;
public final int modelViewInverseUniform;
public final int projectionUniform;
public final int projectionInverseUniform;
public final int normalMatrix3fUniform;
// Fog/Clip Uniforms
public final int clipDistanceUniform;
private final int id;
private final ProgramUniforms uniforms;
private final CustomUniforms customUniforms;
private final ProgramSamplers samplers;
private final ProgramImages images;
private final BlendModeOverride blend;
private final BufferBlendOverride[] bufferBlendOverrides;
private final Matrix4f tempMat4a = new Matrix4f();
private final Matrix4f tempMat4b = new Matrix4f();
private final Matrix3f tempMat3 = new Matrix3f();
// This will bind AbstractVertexAttribute
private IrisLodRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) {
id = GLStateManager.glCreateProgram();
GLStateManager.glBindAttribLocation(this.id, 0, "vPosition");
GLStateManager.glBindAttribLocation(this.id, 1, "iris_color");
GLStateManager.glBindAttribLocation(this.id, 2, "irisExtra");
this.bufferBlendOverrides = bufferBlendOverrides;
GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex);
GLStateManager.glAttachShader(id, vert.getHandle());
GlShader tessCont = null;
if (tessControl != null) {
tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl);
GLStateManager.glAttachShader(id, tessCont.getHandle());
}
GlShader tessE = null;
if (tessEval != null) {
tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval);
GLStateManager.glAttachShader(id, tessE.getHandle());
}
GlShader geom = null;
if (geometry != null) {
geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry);
GLStateManager.glAttachShader(id, geom.getHandle());
}
GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment);
GLStateManager.glAttachShader(id, frag.getHandle());
GLStateManager.glLinkProgram(this.id);
int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
if (status != 1) {
String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999);
this.free();
throw new RuntimeException(message);
} else {
GLStateManager.glUseProgram(this.id);
}
vert.destroy();
frag.destroy();
if (tessCont != null) tessCont.destroy();
if (tessE != null) tessE.destroy();
if (geom != null) geom.destroy();
blend = override;
ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id);
ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX);
customUniforms.assignTo(uniformBuilder);
BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder);
ProgramImages.Builder builder = ProgramImages.builder(id);
pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder,
isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(),
isShadowPass, true, true, false);
customUniforms.mapholderToPass(uniformBuilder, this);
this.uniforms = uniformBuilder.buildUniforms();
this.customUniforms = customUniforms;
samplers = samplerBuilder.build();
images = builder.build();
modelOffsetUniform = tryGetUniformLocation2("modelOffset");
worldYOffsetUniform = tryGetUniformLocation2("worldYOffset");
mircoOffsetUniform = tryGetUniformLocation2("mircoOffset");
projectionUniform = tryGetUniformLocation2("iris_ProjectionMatrix");
projectionInverseUniform = tryGetUniformLocation2("iris_ProjectionMatrixInverse");
modelViewUniform = tryGetUniformLocation2("iris_ModelViewMatrix");
modelViewInverseUniform = tryGetUniformLocation2("iris_ModelViewMatrixInverse");
normalMatrix3fUniform = tryGetUniformLocation2("iris_NormalMatrix");
// Fog/Clip Uniforms
clipDistanceUniform = tryGetUniformLocation2("clipDistance");
}
public static IrisLodRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) {
Map<PatchShaderType, String> transformed = TransformPatcher.patchDHTerrain(
name,
source.getVertexSource().orElseThrow(RuntimeException::new),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getGeometrySource().orElse(null),
source.getFragmentSource().orElseThrow(RuntimeException::new),
pipeline.getTextureMap());
String vertex = transformed.get(PatchShaderType.VERTEX);
String tessControl = transformed.get(PatchShaderType.TESS_CONTROL);
String tessEval = transformed.get(PatchShaderType.TESS_EVAL);
String geometry = transformed.get(PatchShaderType.GEOMETRY);
String fragment = transformed.get(PatchShaderType.FRAGMENT);
PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, tessControl, tessEval, fragment);
List<BufferBlendOverride> bufferOverrides = new ArrayList<>();
source.getDirectives().getBufferBlendOverrides().forEach(information -> {
int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex());
if (index > -1) {
bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode()));
}
});
return new IrisLodRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline);
}
// Noise Uniforms
public int tryGetUniformLocation2(CharSequence name) {
return GLStateManager.glGetUniformLocation(this.id, name);
}
public void setUniform(int index, Matrix4fc matrix) {
if (index == -1 || matrix == null) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(16);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix4(index, false, buffer);
}
}
public void setUniform(int index, Matrix3f matrix) {
if (index == -1) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(9);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix3(index, false, buffer);
}
}
// Override ShaderProgram.bind()
public void bind() {
GLStateManager.glUseProgram(id);
if (blend != null) blend.apply();
for (BufferBlendOverride override : bufferBlendOverrides) {
override.apply();
}
}
public void unbind() {
GLStateManager.glUseProgram(0);
ProgramUniforms.clearActiveUniforms();
ProgramSamplers.clearActiveSamplers();
BlendModeOverride.restore();
}
public void free() {
GLStateManager.glDeleteProgram(id);
}
public void fillUniformData(Matrix4fc projection, Matrix4fc modelView, int worldYOffset, float partialTicks) {
GLStateManager.glUseProgram(id);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT);
DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture();
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId());
setUniform(modelViewUniform, modelView);
setUniform(modelViewInverseUniform, modelView.invert(tempMat4a));
setUniform(projectionUniform, projection);
setUniform(projectionInverseUniform, projection.invert(tempMat4b));
setUniform(normalMatrix3fUniform, tempMat4a.set(modelView).invert().transpose3x3(tempMat3));
setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset
// setUniform(skyLightUniform, skyLight);
if (worldYOffsetUniform != -1) setUniform(worldYOffsetUniform, (float) worldYOffset);
// Fog/Clip Uniforms
float dhNearClipDistance = DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(partialTicks);
setUniform(clipDistanceUniform, dhNearClipDistance);
samplers.update();
uniforms.update();
customUniforms.push(this);
images.update();
}
private void setUniform(int index, float value) {
GLStateManager.glUniform1f(index, value);
}
public void setModelPos(DhApiVec3f modelPos) {
setUniform(modelOffsetUniform, modelPos);
}
private void setUniform(int index, DhApiVec3f pos) {
GLStateManager.glUniform3f(index, pos.x, pos.y, pos.z);
}
}
@@ -0,0 +1,383 @@
package net.coderbot.iris.compat.dh;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogDrawMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeApplyShaderRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDeferredRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderCleanupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderSetupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeTextureClearEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiColorDepthTextureCreatedEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import net.coderbot.iris.Iris;
import net.coderbot.iris.pipeline.ShadowRenderer;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
import net.coderbot.iris.shadows.ShadowRenderingState;
import net.coderbot.iris.uniforms.CapturedRenderingState;
import net.irisshaders.iris.api.v0.IrisApi;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
public class LodRendererEvents {
// TODO: Query actual world min height for Cubic Chunks compatibility
private static final int WORLD_MIN_Y = 0;
private static boolean eventHandlersBound = false;
private static boolean atTranslucent = false;
private static int textureWidth;
private static int textureHeight;
private static final Matrix4f tempMat4 = new Matrix4f();
// constructor //
public static void setupEventHandlers() {
if (!eventHandlersBound) {
eventHandlersBound = true;
Iris.logger.info("Queuing DH event binding...");
DhApiAfterDhInitEvent beforeCleanupEvent = new DhApiAfterDhInitEvent() {
@Override
public void afterDistantHorizonsInit(DhApiEventParam<Void> event) {
Iris.logger.info("DH Ready, binding Iris event handlers...");
Iris.loadShaderpackWhenPossible();
setupSetDeferredBeforeRenderingEvent();
setupReconnectDepthTextureEvent();
setupGenericEvent();
setupCreateDepthTextureEvent();
setupTransparentRendererEventCancling();
setupBeforeBufferClearEvent();
setupBeforeRenderCleanupEvent();
beforeBufferRenderEvent();
setupBeforeRenderFrameBufferBinding();
setupBeforeRenderPassEvent();
setupBeforeApplyShaderEvent();
DHCompatInternal.dhEnabled = DhApi.Delayed.configs.graphics().renderingEnabled().getValue();
Iris.logger.info("DH Iris events bound.");
}
};
DhApi.events.bind(DhApiAfterDhInitEvent.class, beforeCleanupEvent);
}
}
// setup event handlers //
private static void setupSetDeferredBeforeRenderingEvent() {
DhApiBeforeRenderEvent beforeRenderEvent = new DhApiBeforeRenderEvent() {
// this event is called before DH starts any rendering prep
// canceling it will prevent DH from rendering for that frame
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
DhApi.Delayed.renderProxy.setDeferTransparentRendering(IrisApi.getInstance().isShaderPackInUse() && getInstance().shouldOverride);
DhApi.Delayed.configs.graphics().fog().drawMode().setValue(getInstance().shouldOverride ? EDhApiFogDrawMode.FOG_DISABLED : EDhApiFogDrawMode.FOG_ENABLED);
}
};
DhApi.events.bind(DhApiBeforeRenderEvent.class, beforeRenderEvent);
}
private static void setupReconnectDepthTextureEvent() {
DhApiBeforeTextureClearEvent beforeRenderEvent = new DhApiBeforeTextureClearEvent() {
@Override
public void beforeClear(DhApiCancelableEventParam<DhApiRenderParam> event) {
var getResult = DhApi.Delayed.renderProxy.getDhDepthTextureId();
if (getResult.success) {
int depthTextureId = getResult.payload;
getInstance().reconnectDHTextures(depthTextureId);
}
}
};
DhApi.events.bind(DhApiBeforeTextureClearEvent.class, beforeRenderEvent);
}
private static void setupGenericEvent() {
DhApiBeforeGenericRenderSetupEvent beforeRenderEvent = new DhApiBeforeGenericRenderSetupEvent() {
@Override
public void beforeSetup(DhApiEventParam<DhApiRenderParam> dhApiEventParam) {
if (getInstance().getGenericFB() != null) {
getInstance().getGenericFB().bind();
}
}
};
DhApiBeforeGenericObjectRenderEvent beforeDrawEvent = new DhApiBeforeGenericObjectRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<EventParam> dhApiCancelableEventParam) {
if (dhApiCancelableEventParam.value.resourceLocationPath.equalsIgnoreCase("Clouds")) {
if (getInstance().avoidRenderingClouds()) {
dhApiCancelableEventParam.cancelEvent();
}
}
}
};
DhApi.events.bind(DhApiBeforeGenericRenderSetupEvent.class, beforeRenderEvent);
DhApi.events.bind(DhApiBeforeGenericObjectRenderEvent.class, beforeDrawEvent);
}
private static DHCompatInternal getInstance() {
return Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::getDHCompat).map(DHCompat::getInstance).orElse(DHCompatInternal.SHADERLESS);
}
private static void setupCreateDepthTextureEvent() {
DhApiColorDepthTextureCreatedEvent beforeRenderEvent = new DhApiColorDepthTextureCreatedEvent() {
@Override
public void onResize(DhApiEventParam<EventParam> input) {
textureWidth = input.value.newWidth;
textureHeight = input.value.newHeight;
}
};
DhApi.events.bind(DhApiColorDepthTextureCreatedEvent.class, beforeRenderEvent);
}
private static void setupTransparentRendererEventCancling() {
DhApiBeforeRenderEvent beforeRenderEvent = new DhApiBeforeRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && (!getInstance().shouldOverrideShadow)) {
event.cancelEvent();
}
}
};
DhApiBeforeDeferredRenderEvent beforeRenderEvent2 = new DhApiBeforeDeferredRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && (!getInstance().shouldOverrideShadow)) {
event.cancelEvent();
}
}
};
DhApi.events.bind(DhApiBeforeRenderEvent.class, beforeRenderEvent);
DhApi.events.bind(DhApiBeforeDeferredRenderEvent.class, beforeRenderEvent2);
}
private static void setupBeforeRenderCleanupEvent() {
DhApiBeforeRenderCleanupEvent beforeCleanupEvent = new DhApiBeforeRenderCleanupEvent() {
@Override
public void beforeCleanup(DhApiEventParam<DhApiRenderParam> event) {
if (getInstance().shouldOverride) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
getInstance().getShadowShader().unbind();
} else {
getInstance().getSolidShader().unbind();
if (atTranslucent) {
GLStateManager.enableCull();
}
}
}
}
};
DhApi.events.bind(DhApiBeforeRenderCleanupEvent.class, beforeCleanupEvent);
}
private static void setupBeforeBufferClearEvent() {
DhApiBeforeTextureClearEvent beforeCleanupEvent = new DhApiBeforeTextureClearEvent() {
@Override
public void beforeClear(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (event.value.renderPass == EDhApiRenderPass.OPAQUE) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
event.cancelEvent();
} else if (getInstance().shouldOverride) {
GLStateManager.glClear(GL11.GL_DEPTH_BUFFER_BIT);
event.cancelEvent();
}
}
}
};
DhApi.events.bind(DhApiBeforeTextureClearEvent.class, beforeCleanupEvent);
}
private static void beforeBufferRenderEvent() {
DhApiBeforeBufferRenderEvent beforeCleanupEvent = new DhApiBeforeBufferRenderEvent() {
@Override
public void beforeRender(DhApiEventParam<EventParam> input) {
DHCompatInternal instance = getInstance();
if (instance.shouldOverride) {
DhApiVec3f modelPos = input.value.modelPos;
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().bind();
instance.getShadowShader().setModelPos(modelPos);
} else if (atTranslucent) {
instance.getTranslucentShader().bind();
instance.getTranslucentShader().setModelPos(modelPos);
} else {
instance.getSolidShader().bind();
instance.getSolidShader().setModelPos(modelPos);
}
}
}
};
DhApi.events.bind(DhApiBeforeBufferRenderEvent.class, beforeCleanupEvent);
}
private static void setupBeforeRenderFrameBufferBinding() {
DhApiBeforeRenderSetupEvent beforeRenderPassEvent = new DhApiBeforeRenderSetupEvent() {
@Override
public void beforeSetup(DhApiEventParam<DhApiRenderParam> event) {
DHCompatInternal instance = getInstance();
OverrideInjector.INSTANCE.unbind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM);
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getShadowFBWrapper());
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getSolidFBWrapper());
OverrideInjector.INSTANCE.unbind(IDhApiGenericObjectShaderProgram.class, instance.getGenericShader());
if (instance.shouldOverride) {
if (instance.getGenericShader() != null) {
OverrideInjector.INSTANCE.bind(IDhApiGenericObjectShaderProgram.class, instance.getGenericShader());
}
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && instance.shouldOverrideShadow) {
OverrideInjector.INSTANCE.bind(IDhApiFramebuffer.class, instance.getShadowFBWrapper());
OverrideInjector.INSTANCE.bind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM);
} else {
OverrideInjector.INSTANCE.bind(IDhApiFramebuffer.class, instance.getSolidFBWrapper());
}
}
}
};
DhApi.events.bind(DhApiBeforeRenderSetupEvent.class, beforeRenderPassEvent);
}
private static void setupBeforeRenderPassEvent() {
DhApiBeforeRenderPassEvent beforeCleanupEvent = new DhApiBeforeRenderPassEvent() {
@Override
public void beforeRender(DhApiEventParam<DhApiRenderParam> event) {
DHCompatInternal instance = getInstance();
// config overrides
if (instance.shouldOverride) {
DhApi.Delayed.configs.graphics().ambientOcclusion().enabled().setValue(false);
DhApi.Delayed.configs.graphics().fog().drawMode().setValue(EDhApiFogDrawMode.FOG_DISABLED);
if (event.value.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT) {
Iris.logger.error("Unexpected; somehow the Opaque + Translucent pass ran with shaders on.");
}
} else {
DhApi.Delayed.configs.graphics().ambientOcclusion().enabled().clearValue();
DhApi.Delayed.configs.graphics().fog().drawMode().clearValue();
}
// cleanup
if (event.value.renderPass == EDhApiRenderPass.OPAQUE) {
if (instance.shouldOverride) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().bind();
} else {
instance.getSolidShader().bind();
}
atTranslucent = false;
}
}
// opaque
if (event.value.renderPass == EDhApiRenderPass.OPAQUE) {
float partialTicks = event.value.partialTicks;
if (instance.shouldOverride) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().fillUniformData(
ShadowRenderer.PROJECTION, ShadowRenderer.MODELVIEW,
WORLD_MIN_Y,
partialTicks);
} else {
Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();;
instance.getSolidShader().fillUniformData(
tempMat4.setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), event.value.nearClipPlane, event.value.farClipPlane),
RenderingState.INSTANCE.getModelViewMatrix(),
WORLD_MIN_Y,
partialTicks);
}
}
}
// transparent
if (event.value.renderPass == EDhApiRenderPass.TRANSPARENT) {
float partialTicks = event.value.partialTicks;
int depthTextureId = DhApi.Delayed.renderProxy.getDhDepthTextureId().payload;
if (instance.shouldOverrideShadow && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().bind();
instance.getShadowFB().bind();
atTranslucent = true;
return;
}
if (instance.shouldOverride && instance.getTranslucentFB() != null) {
instance.copyTranslucents(textureWidth, textureHeight);
instance.getTranslucentShader().bind();
Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();
GLStateManager.disableCull();
instance.getTranslucentShader().fillUniformData(
new Matrix4f().setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), event.value.nearClipPlane, event.value.farClipPlane),
RenderingState.INSTANCE.getModelViewMatrix(),
WORLD_MIN_Y,
partialTicks);
instance.getTranslucentFB().bind();
}
atTranslucent = true;
}
}
};
DhApi.events.bind(DhApiBeforeRenderPassEvent.class, beforeCleanupEvent);
}
private static void setupBeforeApplyShaderEvent() {
DhApiBeforeApplyShaderRenderEvent beforeApplyShaderEvent = new DhApiBeforeApplyShaderRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (IrisApi.getInstance().isShaderPackInUse()) {
DHCompatInternal instance = getInstance();
OverrideInjector.INSTANCE.unbind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM);
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getShadowFBWrapper());
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getSolidFBWrapper());
event.cancelEvent();
}
}
};
DhApi.events.bind(DhApiBeforeApplyShaderRenderEvent.class, beforeApplyShaderEvent);
}
}
@@ -33,12 +33,18 @@ public class IrisConfig {
*/
private boolean disableUpdateMessage;
/**
* If debug features should be enabled. Gives much more detailed OpenGL error outputs at the cost of performance.
*/
private boolean enableDebugOptions;
private final Path propertiesPath;
public IrisConfig(Path propertiesPath) {
shaderPackName = null;
enableShaders = true;
disableUpdateMessage = false;
enableDebugOptions = false;
this.propertiesPath = propertiesPath;
}
@@ -103,6 +109,10 @@ public class IrisConfig {
this.enableShaders = enabled;
}
public boolean areDebugOptionsEnabled() {
return enableDebugOptions;
}
/**
* loads the config file and then populates the string, int, and boolean entries with the parsed entries
*
@@ -121,6 +131,7 @@ public class IrisConfig {
}
shaderPackName = properties.getProperty("shaderPack");
enableShaders = !"false".equals(properties.getProperty("enableShaders"));
enableDebugOptions = "true".equals(properties.getProperty("enableDebugOptions"));
disableUpdateMessage = "true".equals(properties.getProperty("disableUpdateMessage"));
// TODO: GUI
try {
@@ -147,6 +158,7 @@ public class IrisConfig {
final Properties properties = new Properties();
properties.setProperty("shaderPack", getShaderPackName().orElse(""));
properties.setProperty("enableShaders", enableShaders ? "true" : "false");
properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false");
properties.setProperty("disableUpdateMessage", disableUpdateMessage ? "true" : "false");
properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance));
// NB: This uses ISO-8859-1 with unicode escapes as the encoding
@@ -45,6 +45,12 @@ public class GlFramebuffer extends GlResource {
this.hasDepthAttachment = true;
}
public void addDepthAttachmentBypass(int texture) {
final int fb = getGlId();
RenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0);
this.hasDepthAttachment = true;
}
public void addColorAttachment(int index, int texture) {
final int fb = getGlId();
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.angelica.Tags;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import cpw.mods.fml.common.Loader;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.parsing.BiomeCategories;
import net.coderbot.iris.pipeline.HandRenderer;
import net.coderbot.iris.pipeline.WorldRenderingPhase;
@@ -77,10 +78,32 @@ public class StandardMacros {
define(standardDefines, "MC_SPECULAR_MAP");
define(standardDefines, "MC_RENDER_QUALITY", "1.0");
define(standardDefines, "MC_SHADOW_QUALITY", "1.0");
define(standardDefines, "IS_ANGELICA");
if (AngelicaConfig.defineIsIris) {
define(standardDefines, "IS_IRIS");
}
define(standardDefines, "IS_ANGELICA");
if (AngelicaConfig.defineIsIris) {
define(standardDefines, "IS_IRIS");
}
if (DHCompat.hasRenderingEnabled()) {
define(standardDefines, "DISTANT_HORIZONS");
}
define(standardDefines, "DH_BLOCK_UNKNOWN", String.valueOf(0));
define(standardDefines, "DH_BLOCK_LEAVES", String.valueOf(1));
define(standardDefines, "DH_BLOCK_STONE", String.valueOf(2));
define(standardDefines, "DH_BLOCK_WOOD", String.valueOf(3));
define(standardDefines, "DH_BLOCK_METAL", String.valueOf(4));
define(standardDefines, "DH_BLOCK_DIRT", String.valueOf(5));
define(standardDefines, "DH_BLOCK_LAVA", String.valueOf(6));
define(standardDefines, "DH_BLOCK_DEEPSLATE", String.valueOf(7));
define(standardDefines, "DH_BLOCK_SNOW", String.valueOf(8));
define(standardDefines, "DH_BLOCK_SAND", String.valueOf(9));
define(standardDefines, "DH_BLOCK_TERRACOTTA", String.valueOf(10));
define(standardDefines, "DH_BLOCK_NETHER_STONE", String.valueOf(11));
define(standardDefines, "DH_BLOCK_WATER", String.valueOf(12));
define(standardDefines, "DH_BLOCK_GRASS", String.valueOf(13));
define(standardDefines, "DH_BLOCK_AIR", String.valueOf(14));
define(standardDefines, "DH_BLOCK_ILLUMINATED", String.valueOf(15));
define(standardDefines, "ANGELICA_VERSION", makeAngelicaVersion());
define(standardDefines, "MC_HAND_DEPTH", Float.toString(HandRenderer.DEPTH));
@@ -1,9 +1,16 @@
package net.coderbot.iris.gl.state;
/**
* Holds update notifiers for PBR texture changes.
* Holds some standard update notifiers for various elements of GL state.
*/
public class StateUpdateNotifiers {
public static ValueUpdateNotifier fogModeNotifier;
public static ValueUpdateNotifier fogStartNotifier;
public static ValueUpdateNotifier fogEndNotifier;
public static ValueUpdateNotifier fogDensityNotifier;
public static ValueUpdateNotifier blendFuncNotifier;
public static ValueUpdateNotifier bindTextureNotifier;
public static ValueUpdateNotifier normalTextureChangeNotifier;
public static ValueUpdateNotifier specularTextureChangeNotifier;
public static ValueUpdateNotifier phaseChangeNotifier;
}
@@ -1,10 +1,10 @@
package net.coderbot.iris.gl.uniform;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector2i;
import org.joml.Vector3i;
import org.joml.Vector4f;
import org.joml.Vector4i;
import org.joml.Vector2ic;
import org.joml.Vector3ic;
import org.joml.Vector4fc;
import org.joml.Vector4ic;
import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
@@ -37,19 +37,19 @@ public interface DynamicLocationalUniformHolder extends LocationalUniformHolder,
return this;
}
default DynamicLocationalUniformHolder uniform2i(String name, Supplier<Vector2i> value, ValueUpdateNotifier notifier) {
default DynamicLocationalUniformHolder uniform2i(String name, Supplier<Vector2ic> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC2I).ifPresent(id -> addDynamicUniform(new Vector2IntegerJomlUniform(id, value, notifier), notifier));
return this;
}
default DynamicUniformHolder uniform3i(String name, Supplier<Vector3i> value, ValueUpdateNotifier notifier) {
default DynamicUniformHolder uniform3i(String name, Supplier<Vector3ic> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC3I).ifPresent(id -> addDynamicUniform(new Vector3IntegerJomlUniform(id, value, notifier), notifier));
return this;
}
default DynamicUniformHolder uniform4f(String name, Supplier<Vector4f> value, ValueUpdateNotifier notifier) {
default DynamicUniformHolder uniform4f(String name, Supplier<Vector4fc> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC4).ifPresent(id -> addDynamicUniform(new Vector4Uniform(id, value, notifier), notifier));
return this;
@@ -60,7 +60,7 @@ public interface DynamicLocationalUniformHolder extends LocationalUniformHolder,
return this;
}
default DynamicUniformHolder uniform4i(String name, Supplier<Vector4i> value, ValueUpdateNotifier notifier) {
default DynamicUniformHolder uniform4i(String name, Supplier<Vector4ic> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC4I).ifPresent(id -> addDynamicUniform(new Vector4IntegerJomlUniform(id, value, notifier), notifier));
return this;
@@ -1,10 +1,10 @@
package net.coderbot.iris.gl.uniform;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector2i;
import org.joml.Vector3i;
import org.joml.Vector4f;
import org.joml.Vector4i;
import org.joml.Vector2ic;
import org.joml.Vector3ic;
import org.joml.Vector4fc;
import org.joml.Vector4ic;
import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
@@ -15,9 +15,9 @@ public interface DynamicUniformHolder extends UniformHolder {
DynamicUniformHolder uniform1f(String name, IntSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform1f(String name, DoubleSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform2i(String name, Supplier<Vector2i> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform3i(String name, Supplier<Vector3i> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4f(String name, Supplier<Vector4f> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform2i(String name, Supplier<Vector2ic> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform3i(String name, Supplier<Vector3ic> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4f(String name, Supplier<Vector4fc> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4fArray(String name, Supplier<float[]> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4i(String name, Supplier<Vector4i> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4i(String name, Supplier<Vector4ic> value, ValueUpdateNotifier notifier);
}
@@ -2,12 +2,15 @@ package net.coderbot.iris.gl.uniform;
import net.minecraft.util.Vec3;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector2f;
import org.joml.Vector2i;
import org.joml.Vector2ic;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector3i;
import org.joml.Vector4f;
import org.joml.Vector3ic;
import org.joml.Vector4fc;
import java.util.OptionalInt;
import java.util.function.BooleanSupplier;
@@ -63,21 +66,21 @@ public interface LocationalUniformHolder extends UniformHolder {
}
@Override
default LocationalUniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2i> value) {
default LocationalUniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2ic> value) {
location(name, UniformType.VEC2I).ifPresent(id -> addUniform(updateFrequency, new Vector2IntegerJomlUniform(id, value)));
return this;
}
@Override
default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3f> value) {
default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3fc> value) {
location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, new Vector3Uniform(id, value)));
return this;
}
@Override
default LocationalUniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3i> value) {
default LocationalUniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3ic> value) {
location(name, UniformType.VEC3I).ifPresent(id -> addUniform(updateFrequency, new Vector3IntegerJomlUniform(id, value)));
return this;
@@ -91,7 +94,7 @@ public interface LocationalUniformHolder extends UniformHolder {
}
@Override
default LocationalUniformHolder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4f> value) {
default LocationalUniformHolder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4fc> value) {
location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, Vector3Uniform.truncated(id, value)));
return this;
@@ -105,7 +108,7 @@ public interface LocationalUniformHolder extends UniformHolder {
}
@Override
default LocationalUniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4f> value) {
default LocationalUniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4fc> value) {
location(name, UniformType.VEC4).ifPresent(id -> addUniform(updateFrequency, new Vector4Uniform(id, value)));
return this;
@@ -119,7 +122,7 @@ public interface LocationalUniformHolder extends UniformHolder {
}
@Override
default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4f> value) {
default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4fc> value) {
location(name, UniformType.MAT4).ifPresent(id -> addUniform(updateFrequency, new MatrixUniform(id, value)));
return this;
@@ -2,6 +2,7 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
@@ -10,9 +11,9 @@ import java.util.function.Supplier;
public class MatrixUniform extends Uniform {
private final FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
private Matrix4f cachedValue;
private final Supplier<Matrix4f> value;
private final Supplier<Matrix4fc> value;
MatrixUniform(int location, Supplier<Matrix4f> value) {
MatrixUniform(int location, Supplier<Matrix4fc> value) {
super(location);
this.cachedValue = null;
@@ -21,7 +22,7 @@ public class MatrixUniform extends Uniform {
@Override
public void update() {
final Matrix4f newValue = value.get();
final Matrix4fc newValue = value.get();
if( newValue == null ){
throw new RuntimeException("MatrixUniform value is null");
}
@@ -1,13 +1,14 @@
package net.coderbot.iris.gl.uniform;
import net.minecraft.util.Vec3;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector2f;
import org.joml.Vector2i;
import org.joml.Vector2ic;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector3i;
import org.joml.Vector4f;
import org.joml.Vector3ic;
import org.joml.Vector4fc;
import java.util.function.BooleanSupplier;
import java.util.function.DoubleSupplier;
@@ -27,23 +28,23 @@ public interface UniformHolder {
UniformHolder uniform2f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2f> value);
UniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2i> value);
UniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2ic> value);
UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3f> value);
UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3fc> value);
UniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3i> value);
UniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3ic> value);
UniformHolder uniformVanilla3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vec3> value);
UniformHolder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4f> value);
UniformHolder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4fc> value);
UniformHolder uniform3d(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3d> value);
UniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4f> value);
UniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4fc> value);
UniformHolder uniform4fArray(UniformUpdateFrequency updateFrequency, String name, Supplier<float[]> value);
UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4f> value);
UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4fc> value);
UniformHolder uniformMatrixFromArray(UniformUpdateFrequency updateFrequency, String name, Supplier<float[]> value);
@@ -3,21 +3,22 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector2i;
import org.joml.Vector2ic;
import java.util.function.Supplier;
public class Vector2IntegerJomlUniform extends Uniform {
private Vector2i cachedValue;
private final Supplier<Vector2i> value;
private final Vector2i cachedValue;
private final Supplier<Vector2ic> value;
Vector2IntegerJomlUniform(int location, Supplier<Vector2i> value) {
Vector2IntegerJomlUniform(int location, Supplier<Vector2ic> value) {
this(location, value, null);
}
Vector2IntegerJomlUniform(int location, Supplier<Vector2i> value, ValueUpdateNotifier notifier) {
Vector2IntegerJomlUniform(int location, Supplier<Vector2ic> value, ValueUpdateNotifier notifier) {
super(location, notifier);
this.cachedValue = null;
this.cachedValue = new Vector2i();
this.value = value;
}
@@ -31,11 +32,11 @@ public class Vector2IntegerJomlUniform extends Uniform {
}
private void updateValue() {
Vector2i newValue = value.get();
Vector2ic newValue = value.get();
if (cachedValue == null || !newValue.equals(cachedValue)) {
cachedValue = newValue;
RenderSystem.uniform2i(this.location, newValue.x, newValue.y);
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y());
RenderSystem.uniform2i(this.location, cachedValue.x, cachedValue.y);
}
}
}
@@ -3,21 +3,22 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import java.util.function.Supplier;
public class Vector3IntegerJomlUniform extends Uniform {
private Vector3i cachedValue;
private final Supplier<Vector3i> value;
private final Vector3i cachedValue;
private final Supplier<Vector3ic> value;
Vector3IntegerJomlUniform(int location, Supplier<Vector3i> value) {
Vector3IntegerJomlUniform(int location, Supplier<Vector3ic> value) {
this(location, value, null);
}
Vector3IntegerJomlUniform(int location, Supplier<Vector3i> value, ValueUpdateNotifier notifier) {
Vector3IntegerJomlUniform(int location, Supplier<Vector3ic> value, ValueUpdateNotifier notifier) {
super(location, notifier);
this.cachedValue = null;
this.cachedValue = new Vector3i();
this.value = value;
}
@@ -31,11 +32,11 @@ public class Vector3IntegerJomlUniform extends Uniform {
}
private void updateValue() {
Vector3i newValue = value.get();
Vector3ic newValue = value.get();
if (cachedValue == null || !newValue.equals(cachedValue)) {
cachedValue = newValue;
RenderSystem.uniform3i(this.location, newValue.x, newValue.y, newValue.z);
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y(), newValue.z());
RenderSystem.uniform3i(this.location, cachedValue.x(), cachedValue.y(), cachedValue.z());
}
}
}
@@ -3,15 +3,16 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.joml.Vector3fc;
import org.joml.Vector4fc;
import java.util.function.Supplier;
public class Vector3Uniform extends Uniform {
private final Vector3f cachedValue;
private final Supplier<Vector3f> value;
private final Supplier<Vector3fc> value;
Vector3Uniform(int location, Supplier<Vector3f> value) {
Vector3Uniform(int location, Supplier<Vector3fc> value) {
super(location);
this.cachedValue = new Vector3f();
@@ -30,11 +31,11 @@ public class Vector3Uniform extends Uniform {
});
}
static Vector3Uniform truncated(int location, Supplier<Vector4f> value) {
static Vector3Uniform truncated(int location, Supplier<Vector4fc> value) {
Vector3f held = new Vector3f();
return new Vector3Uniform(location, () -> {
Vector4f updated = value.get();
Vector4fc updated = value.get();
held.set(updated.x(), updated.y(), updated.z());
@@ -44,7 +45,7 @@ public class Vector3Uniform extends Uniform {
@Override
public void update() {
Vector3f newValue = value.get();
Vector3fc newValue = value.get();
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y(), newValue.z());
@@ -3,21 +3,22 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector4i;
import org.joml.Vector4ic;
import java.util.function.Supplier;
public class Vector4IntegerJomlUniform extends Uniform {
private Vector4i cachedValue;
private final Supplier<Vector4i> value;
private final Vector4i cachedValue;
private final Supplier<Vector4ic> value;
Vector4IntegerJomlUniform(int location, Supplier<Vector4i> value) {
Vector4IntegerJomlUniform(int location, Supplier<Vector4ic> value) {
this(location, value, null);
}
Vector4IntegerJomlUniform(int location, Supplier<Vector4i> value, ValueUpdateNotifier notifier) {
Vector4IntegerJomlUniform(int location, Supplier<Vector4ic> value, ValueUpdateNotifier notifier) {
super(location, notifier);
this.cachedValue = null;
this.cachedValue = new Vector4i();
this.value = value;
}
@@ -31,11 +32,11 @@ public class Vector4IntegerJomlUniform extends Uniform {
}
private void updateValue() {
Vector4i newValue = value.get();
Vector4ic newValue = value.get();
if (cachedValue == null || !newValue.equals(cachedValue)) {
cachedValue = newValue;
RenderSystem.uniform4i(this.location, newValue.x, newValue.y, newValue.z, newValue.w);
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y(), newValue.z(), newValue.w());
RenderSystem.uniform4i(this.location, cachedValue.x, cachedValue.y, cachedValue.z, cachedValue.w);
}
}
}
@@ -3,18 +3,19 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector4f;
import org.joml.Vector4fc;
import java.util.function.Supplier;
public class Vector4Uniform extends Uniform {
private final Vector4f cachedValue;
private final Supplier<Vector4f> value;
private final Supplier<Vector4fc> value;
Vector4Uniform(int location, Supplier<Vector4f> value) {
Vector4Uniform(int location, Supplier<Vector4fc> value) {
this(location, value, null);
}
Vector4Uniform(int location, Supplier<Vector4f> value, ValueUpdateNotifier notifier) {
Vector4Uniform(int location, Supplier<Vector4fc> value, ValueUpdateNotifier notifier) {
super(location, notifier);
this.cachedValue = new Vector4f();
@@ -31,7 +32,7 @@ public class Vector4Uniform extends Uniform {
}
private void updateValue() {
Vector4f newValue = value.get();
Vector4fc newValue = value.get();
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y(), newValue.z(), newValue.w());
@@ -1,7 +1,7 @@
package net.coderbot.iris.gui.screen;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import net.coderbot.iris.Iris;
import net.coderbot.iris.gui.GuiUtil;
import net.coderbot.iris.gui.NavigationController;
@@ -460,7 +460,7 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
}
if (openViaSystemClass) {
AngelicaTweaker.LOGGER.debug("Opening via system class!");
AngelicaMod.LOGGER.debug("Opening via system class!");
Sys.openURL("file://" + uri);
}
}
@@ -4,6 +4,7 @@ import net.coderbot.iris.Iris;
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import net.coderbot.iris.gl.shader.ProgramCreator;
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
import net.coderbot.iris.pipeline.WorldRenderingPhase;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
@@ -11,7 +12,12 @@ public class GbufferPrograms {
private static boolean entities;
private static boolean blockEntities;
private static boolean outline;
private static Runnable phaseChangeListener;
static {
StateUpdateNotifiers.phaseChangeNotifier = listener -> phaseChangeListener = listener;
}
private static void checkReentrancy() {
if (entities || blockEntities || outline) {
throw new IllegalStateException("GbufferPrograms in weird state, tried to call begin function when entities = "
@@ -106,7 +112,13 @@ public class GbufferPrograms {
public static void teardownSpecialRenderCondition() {
Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(null));
}
public static void runPhaseChangeNotifier() {
if (phaseChangeListener != null) {
phaseChangeListener.run();
}
}
public static void init() {
// Empty initializer to run static
}
@@ -29,16 +29,19 @@ import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder;
import net.coderbot.iris.gl.buffer.ShaderStorageInfo;
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
import net.coderbot.iris.gl.image.GlImage;
import net.coderbot.iris.gl.image.ImageHolder;
import net.coderbot.iris.gl.image.ImageInformation;
import net.coderbot.iris.gl.program.ComputeProgram;
import net.coderbot.iris.gl.program.Program;
import net.coderbot.iris.gl.program.ProgramBuilder;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.sampler.SamplerHolder;
import net.coderbot.iris.gl.state.FogMode;
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.PatchShaderType;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.postprocess.BufferFlipper;
@@ -177,6 +180,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
private final boolean oldLighting;
private final boolean allowConcurrentCompute;
private final OptionalInt forcedShadowRenderDistanceChunks;
private final CloudSetting dhCloudSetting;
private Pass current = null;
@@ -192,21 +196,25 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
private int currentSpecularTexture;
private PackDirectives packDirectives;
private final Set<FeatureFlags> activeFeatures;
private final ProgramFallbackResolver resolver;
public DeferredWorldRenderingPipeline(ProgramSet programs) {
Objects.requireNonNull(programs);
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> prepareTransformFutures = submitCompositeTransforms(programs.getPrepare());
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> deferredTransformFutures = submitCompositeTransforms(programs.getDeferred());
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> compositeTransformFutures = submitCompositeTransforms(programs.getComposite());
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> prepareTransformFutures =
submitCompositeTransforms(programs.getPrepare(), TextureStage.PREPARE, programs.getPackDirectives().getTextureMap());
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> deferredTransformFutures =
submitCompositeTransforms(programs.getDeferred(), TextureStage.DEFERRED, programs.getPackDirectives().getTextureMap());
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> compositeTransformFutures =
submitCompositeTransforms(programs.getComposite(), TextureStage.COMPOSITE_AND_FINAL, programs.getPackDirectives().getTextureMap());
final CompletableFuture<Map<PatchShaderType, String>> finalTransformFuture =
programs.getCompositeFinal()
.filter(ProgramSource::isValid)
.map(DeferredWorldRenderingPipeline::submitCompositeTransform)
.map(source -> submitCompositeTransform(source, TextureStage.COMPOSITE_AND_FINAL, programs.getPackDirectives().getTextureMap()))
.orElse(null);
final ProgramFallbackResolver resolver = new ProgramFallbackResolver(programs);
resolver = new ProgramFallbackResolver(programs);
final Map<Pair<String, InputAvailability>, CompletableFuture<Map<PatchShaderType, String>>> attributeTransformFutures = submitAttributeTransforms(resolver);
final Optional<ProgramSource> terrainSource = first(programs.getGbuffersTerrain(), programs.getGbuffersTexturedLit(), programs.getGbuffersTextured(), programs.getGbuffersBasic());
@@ -228,6 +236,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
this.shouldRenderWeather = programs.getPackDirectives().shouldRenderWeather();
this.shouldRenderWeatherParticles = programs.getPackDirectives().shouldRenderWeatherParticles();
this.shouldWriteRainAndSnowToDepthBuffer = programs.getPackDirectives().rainDepth();
this.dhCloudSetting = programs.getPackDirectives().getDHCloudSetting();
this.shouldRenderParticlesBeforeDeferred = programs.getPackDirectives().getParticleRenderingSettings()
.map(s -> s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.BEFORE || s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.MIXED)
.orElse(false);
@@ -587,7 +596,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
renderTargets, flippedAfterPrepare, flippedAfterTranslucent,
celeritasShadowFb);
this.dhCompat = new DHCompat();
this.dhCompat = new DHCompat(this, shadowDirectives.isDhShadowEnabled().orElse(true));
}
private RenderTargets getRenderTargets() {
@@ -755,14 +764,21 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
return p != null ? p.getProgramId() : -1;
}
/**
* Called when a mod overrides the GL program away from the active Iris pass
*/
public void onModProgramOverride() {
current = null;
}
private void matchPass() {
if (!isRenderingWorld || isRenderingFullScreenPass || isPostChain || !isMainBound) {
return;
}
final RenderCondition condition = getCondition(getPhase());
final Pass matched = table.match(condition, inputs);
beginPass(matched);
}
@@ -909,6 +925,38 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
return pass;
}
public void addGbufferOrShadowSamplers(SamplerHolder samplers, ImageHolder images, Supplier<ImmutableSet<Integer>> flipped,
boolean isShadowPass, boolean hasTexture, boolean hasLightmap, boolean hasOverlay) {
TextureStage textureStage = TextureStage.GBUFFERS_AND_SHADOW;
ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor =
ProgramSamplers.customTextureSamplerInterceptor(samplers, customTextureManager.getCustomTextureIdMap(textureStage));
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false, this);
IrisImages.addRenderTargetImages(images, flipped, renderTargets);
if (!shouldBindPBR) {
shouldBindPBR = IrisSamplers.hasPBRSamplers(customTextureSamplerInterceptor);
}
IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(hasTexture, hasLightmap));
if (!isShadowPass) {
IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets);
}
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture());
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures());
IrisImages.addCustomImages(images, customImages);
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, true);
}
if (isShadowPass || IrisImages.hasShadowImages(images)) {
IrisImages.addShadowColorImages(images, shadowTargetsSupplier.get(), null);
}
}
private boolean isPostChain;
private boolean isMainBound = true;
@@ -940,6 +988,56 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
}
}
public CloudSetting getDHCloudSetting() {
return dhCloudSetting;
}
public Optional<ProgramSource> getDHTerrainShader() {
return resolver.resolve(ProgramId.DhTerrain);
}
public Optional<ProgramSource> getDHGenericShader() {
return resolver.resolve(ProgramId.DhGeneric);
}
public Optional<ProgramSource> getDHWaterShader() {
return resolver.resolve(ProgramId.DhWater);
}
public Optional<ProgramSource> getDHShadowShader() {
return resolver.resolve(ProgramId.DhShadow);
}
public CustomUniforms getCustomUniforms() {
return customUniforms;
}
public GlFramebuffer createDHFramebuffer(ProgramSource sources, boolean trans) {
return renderTargets.createDHFramebuffer(trans ? flippedAfterTranslucent : flippedAfterPrepare,
sources.getDirectives().getDrawBuffers());
}
public ImmutableSet<Integer> getFlippedBeforeShadow() {
return flippedBeforeShadow;
}
public ImmutableSet<Integer> getFlippedAfterPrepare() {
return flippedAfterPrepare;
}
public ImmutableSet<Integer> getFlippedAfterTranslucent() {
return flippedAfterTranslucent;
}
public GlFramebuffer createDHFramebufferShadow(ProgramSource sources) {
return shadowRenderTargets.createDHFramebuffer(ImmutableSet.of(), new int[]{0, 1});
}
public boolean hasShadowRenderTargets() {
return shadowRenderTargets != null;
}
private final class Pass {
@Nullable
private final Program program;
@@ -1087,6 +1185,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
// While it's possible to just clear them instead and reuse them, we'd need to investigate whether or not this
// would help performance.
renderTargets.destroy();
dhCompat.clearPipeline();
// destroy the shadow render targets
if (shadowRenderTargets != null) {
@@ -1558,12 +1657,14 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
public void setOverridePhase(WorldRenderingPhase phase) {
this.overridePhase = phase;
matchPass();
GbufferPrograms.runPhaseChangeNotifier();
}
@Override
public void setPhase(WorldRenderingPhase phase) {
this.phase = phase;
matchPass();
GbufferPrograms.runPhaseChangeNotifier();
}
@Override
@@ -1615,11 +1716,20 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
private static final InputAvailability INPUT_TEXTURE_LIGHTMAP = new InputAvailability(true, true);
private static final InputAvailability[] INPUT_AVAILABILITIES = { INPUT_NONE, INPUT_TEXTURE, INPUT_TEXTURE_LIGHTMAP };
private static CompletableFuture<Map<PatchShaderType, String>> submitCompositeTransform(ProgramSource source) {
return Iris.ShaderTransformExecutor.submitTracked(() -> TransformPatcher.patchComposite(source.getVertexSource().orElse(null), source.getGeometrySource().orElse(null), source.getTessControlSource().orElse(null), source.getTessEvalSource().orElse(null), source.getFragmentSource().orElse(null)));
private static CompletableFuture<Map<PatchShaderType, String>> submitCompositeTransform(ProgramSource source, TextureStage stage,
Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return Iris.ShaderTransformExecutor.submitTracked(() -> TransformPatcher.patchComposite(
source.getVertexSource().orElse(null),
source.getGeometrySource().orElse(null),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getFragmentSource().orElse(null),
stage,
textureMap));
}
private static Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> submitCompositeTransforms(ProgramSource[] sources) {
private static Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> submitCompositeTransforms(ProgramSource[] sources,
TextureStage stage, Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
// Count valid sources for initial capacity
int count = 0;
for (ProgramSource source : sources) {
@@ -1628,7 +1738,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
final Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> futures = new HashMap<>(count);
for (int i = 0; i < sources.length; i++) {
if (sources[i] != null && sources[i].isValid()) {
futures.put(i, submitCompositeTransform(sources[i]));
futures.put(i, submitCompositeTransform(sources[i], stage, textureMap));
}
}
return futures;
@@ -130,7 +130,7 @@ public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeli
return new FrameUpdateNotifier();
}
private static final DHCompat DH_COMPAT = new DHCompat();
private static final DHCompat DH_COMPAT = new DHCompat(null, false);
@Override
public DHCompat getDHCompat() {
@@ -39,53 +39,54 @@ public class PatchedShaderPrinter {
}
public static void debugPatchedShaders(String name, String vertex, String geometry, String tessControl, String tessEval, String fragment, String compute) {
if (prettyPrintShaders) {
final Path debugOutDir = Minecraft.getMinecraft().mcDataDir.toPath().resolve("patched_shaders");
if (!outputLocationCleared) {
try {
if (Files.exists(debugOutDir)) {
try (Stream<Path> stream = Files.list(debugOutDir)) {
stream.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
Files.createDirectories(debugOutDir);
} catch (IOException e) {
Iris.logger.warn("Failed to initialize debug patched shader source location", e);
}
outputLocationCleared = true;
}
if (!prettyPrintShaders && !Iris.getIrisConfig().areDebugOptionsEnabled()) {
return;
}
final Path debugOutDir = Minecraft.getMinecraft().mcDataDir.toPath().resolve("patched_shaders");
if (!outputLocationCleared) {
try {
programCounter++;
String prefix = String.format("%03d_", programCounter);
if (vertex != null) {
Files.write(debugOutDir.resolve(prefix + name + ".vsh"), vertex.getBytes(StandardCharsets.UTF_8));
}
if (geometry != null) {
Files.write(debugOutDir.resolve(prefix + name + ".gsh"), geometry.getBytes(StandardCharsets.UTF_8));
}
if (tessControl != null) {
Files.write(debugOutDir.resolve(prefix + name + ".tcs"), tessControl.getBytes(StandardCharsets.UTF_8));
}
if (tessEval != null) {
Files.write(debugOutDir.resolve(prefix + name + ".tes"), tessEval.getBytes(StandardCharsets.UTF_8));
}
if (fragment != null) {
Files.write(debugOutDir.resolve(prefix + name + ".fsh"), fragment.getBytes(StandardCharsets.UTF_8));
}
if (compute != null) {
Files.write(debugOutDir.resolve(prefix + name + ".csh"), compute.getBytes(StandardCharsets.UTF_8));
if (Files.exists(debugOutDir)) {
try (Stream<Path> stream = Files.list(debugOutDir)) {
stream.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
Files.createDirectories(debugOutDir);
} catch (IOException e) {
Iris.logger.warn("Failed to write debug patched shader source", e);
Iris.logger.warn("Failed to initialize debug patched shader source location", e);
}
outputLocationCleared = true;
}
try {
programCounter++;
String prefix = String.format("%03d_", programCounter);
if (vertex != null) {
Files.write(debugOutDir.resolve(prefix + name + ".vsh"), vertex.getBytes(StandardCharsets.UTF_8));
}
if (geometry != null) {
Files.write(debugOutDir.resolve(prefix + name + ".gsh"), geometry.getBytes(StandardCharsets.UTF_8));
}
if (tessControl != null) {
Files.write(debugOutDir.resolve(prefix + name + ".tcs"), tessControl.getBytes(StandardCharsets.UTF_8));
}
if (tessEval != null) {
Files.write(debugOutDir.resolve(prefix + name + ".tes"), tessEval.getBytes(StandardCharsets.UTF_8));
}
if (fragment != null) {
Files.write(debugOutDir.resolve(prefix + name + ".fsh"), fragment.getBytes(StandardCharsets.UTF_8));
}
if (compute != null) {
Files.write(debugOutDir.resolve(prefix + name + ".csh"), compute.getBytes(StandardCharsets.UTF_8));
}
} catch (IOException e) {
Iris.logger.warn("Failed to write debug patched shader source", e);
}
}
}
@@ -10,6 +10,7 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
import net.coderbot.iris.Iris;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.gui.option.IrisVideoSettings;
import net.coderbot.iris.layer.GbufferPrograms;
import net.coderbot.iris.shaderpack.PackDirectives;
@@ -43,6 +44,7 @@ import net.minecraft.profiler.Profiler;
import net.minecraft.tileentity.TileEntity;
import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
@@ -68,6 +70,8 @@ public class ShadowRenderer {
public static final List<TileEntity> globalTileEntities = new ArrayList<>();
public static boolean ACTIVE = false;
public static Frustrum FRUSTUM;
private static final Comparator<Entity> ENTITY_CLASS_COMPARATOR = Comparator.comparingInt(a -> System.identityHashCode(a.getClass()));
private static final NonCullingFrustum NON_CULLING_FRUSTUM = new NonCullingFrustum();
private static final CullEverythingFrustum CULL_EVERYTHING_FRUSTUM = new CullEverythingFrustum();
@@ -111,12 +115,16 @@ public class ShadowRenderer {
private double lastBoxCullerDistance = -1;
private double lastAdvancedBoxCullerDistance = -1;
private double lastTileEntityCullerDistance = -1;
private final boolean shouldRenderDH;
private final float nearPlane, farPlane;
public ShadowRenderer(ProgramSource shadow, PackDirectives directives, ShadowRenderTargets shadowRenderTargets, ShadowCompositeRenderer compositeRenderer) {
this.profiler = Minecraft.getMinecraft().mcProfiler;
final PackShadowDirectives shadowDirectives = directives.getShadowDirectives();
this.nearPlane = shadowDirectives.getNearPlane();
this.farPlane = shadowDirectives.getFarPlane();
this.halfPlaneLength = shadowDirectives.getDistance();
this.voxelDistance = shadowDirectives.getVoxelDistance();
@@ -129,6 +137,7 @@ public class ShadowRenderer {
this.shouldRenderEntities = shadowDirectives.shouldRenderEntities();
this.shouldRenderPlayer = shadowDirectives.shouldRenderPlayer();
this.shouldRenderBlockEntities = shadowDirectives.shouldRenderBlockEntities();
this.shouldRenderDH = shadowDirectives.isDhShadowEnabled().orElse(false);
this.compositeRenderer = compositeRenderer;
@@ -348,14 +357,16 @@ public class ShadowRenderer {
shadowLightVectorCache.set(shadowLightPosition.x(), shadowLightPosition.y(), shadowLightPosition.z());
shadowLightVectorCache.normalize();
Matrix4fc projView = ((shouldRenderDH && DHCompat.hasRenderingEnabled()) ? DHCompat.getProjection() : RenderingState.INSTANCE.getProjectionMatrix());
if (hasSafeZone) {
BoxCuller distanceCuller = new BoxCuller(halfPlaneLength * renderMultiplier);
SafeZoneCullingFrustum safeZoneFrustum = new SafeZoneCullingFrustum(
RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(),
RenderingState.INSTANCE.getModelViewMatrix(), projView,
shadowLightVectorCache, boxCuller, distanceCuller);
return holder.setInfo(safeZoneFrustum, distanceInfo, cullingInfo);
} else {
cachedAdvancedFrustum.init(RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(), shadowLightVectorCache, boxCuller);
cachedAdvancedFrustum.init(RenderingState.INSTANCE.getModelViewMatrix(), projView, shadowLightVectorCache, boxCuller);
return holder.setInfo(cachedAdvancedFrustum, distanceInfo, cullingInfo);
}
}
@@ -630,12 +641,12 @@ public class ShadowRenderer {
final MatrixStack modelView = getShadowModelView();
MODELVIEW.set(modelView.peek().getModel());
final Matrix4f shadowProjection;
final Matrix4f shadowProjection;
if (this.fov != null) {
// If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs)
shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov);
shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov);
} else {
shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength);
shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength, nearPlane < 0 ? -DHCompat.getRenderDistance() : nearPlane, farPlane < 0 ? DHCompat.getRenderDistance() : farPlane);
}
PROJECTION.set(shadowProjection);
@@ -649,6 +660,7 @@ public class ShadowRenderer {
profiler.startSection("initialize frustum");
terrainFrustumHolder = createShadowFrustum(renderDistanceMultiplier, terrainFrustumHolder);
FRUSTUM = terrainFrustumHolder.getFrustum();
// Use the player/entity position for shadow rendering
final Vector3d entityPos = playerCamera.getEntityPos();
@@ -0,0 +1,114 @@
package net.coderbot.iris.pipeline.transform;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import org.taumc.glsl.Transformer;
public class DHGenericTransformer {
public static void transform(Transformer transformer, Parameters parameters, int glslVersion) {
CommonTransformer.transform(transformer, parameters, true, glslVersion);
transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)");
transformer.replaceExpression("gl_TextureMatrix[1]", "mat4(1.0)");
transformer.rename("gl_ProjectionMatrix", "iris_ProjectionMatrix");
if (parameters.type == ShaderType.VERTEX) {
// Alias of gl_MultiTexCoord1 on 1.15+ for OptiFine
// See https://github.com/IrisShaders/Iris/issues/1149
transformer.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1");
transformer.replaceExpression("gl_MultiTexCoord0", "vec4(0.0, 0.0, 0.0, 1.0)");
transformer.replaceExpression("gl_MultiTexCoord1", "vec4(_vert_tex_light_coord, 0.0, 1.0)");
replaceGlMultiTexCoordBounded(transformer, 4, 7);
}
transformer.rename("gl_Color", "_vert_color");
if (parameters.type == ShaderType.VERTEX) {
transformer.replaceExpression("gl_Normal", "_vert_normal");
}
transformer.replaceExpression("gl_NormalMatrix", "iris_NormalMatrix");
addIfNotExists(transformer, "iris_NormalMatrix", "uniform mat3 iris_NormalMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrixInverse", "uniform mat4 iris_ModelViewMatrixInverse;");
addIfNotExists(transformer, "iris_ProjectionMatrixInverse", "uniform mat4 iris_ProjectionMatrixInverse;");
transformer.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix");
transformer.rename("gl_ModelViewMatrixInverse", "iris_ModelViewMatrixInverse");
transformer.rename("gl_ProjectionMatrixInverse", "iris_ProjectionMatrixInverse");
if (parameters.type == ShaderType.VERTEX) {
if (transformer.containsCall("ftransform")) {
transformer.injectFunction("vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }");
}
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
transformer.injectFunction("vec4 getVertexPosition() { return vec4(_vert_position, 1.0); }");
transformer.replaceExpression("gl_Vertex", "getVertexPosition()");
injectVertInit(transformer);
} else {
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
}
transformer.replaceExpression("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)");
ShaderTransformer.applyIntelHd4000Workaround(transformer);
}
public static void injectVertInit(Transformer transformer) {
addIfNotExists(transformer, "_vert_position", "vec3 _vert_position;");
addIfNotExists(transformer, "_vert_tex_light_coord", "vec2 _vert_tex_light_coord;");
addIfNotExists(transformer, "dhMaterialId", "int dhMaterialId;");
addIfNotExists(transformer, "_vert_color", "vec4 _vert_color;");
addIfNotExists(transformer, "_vert_normal", "vec3 _vert_normal;");
addIfNotExists(transformer, "uOffsetChunk", "uniform ivec3 uOffsetChunk;");
addIfNotExists(transformer, "uOffsetSubChunk", "uniform vec3 uOffsetSubChunk;");
addIfNotExists(transformer, "uCameraPosChunk", "uniform ivec3 uCameraPosChunk;");
addIfNotExists(transformer, "uCameraPosSubChunk", "uniform vec3 uCameraPosSubChunk;");
addIfNotExists(transformer, "uSkyLight", "uniform int uSkyLight;");
addIfNotExists(transformer, "uBlockLight", "uniform int uBlockLight;");
addIfNotExists(transformer, "iris_color", "in vec4 iris_color;");
addIfNotExists(transformer, "aScale", "in vec3 aScale;");
addIfNotExists(transformer, "aTranslateChunk", "in ivec3 aTranslateChunk;");
addIfNotExists(transformer, "aTranslateSubChunk", "in vec3 aTranslateSubChunk;");
addIfNotExists(transformer, "aMaterial", "in int aMaterial;");
addIfNotExists(transformer, "vPosition", "in vec3 vPosition;");
transformer.injectFunction("const vec3 irisNormals[6] = vec3[](vec3(0,0,-1), vec3(0,0,1), vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0));");
transformer.injectFunction(
"void _vert_init() {"
+ " vec3 trans = vec3(aTranslateChunk + uOffsetChunk - uCameraPosChunk) * 16.0;"
+ " trans += (aTranslateSubChunk + uOffsetSubChunk - uCameraPosSubChunk);"
+ " mat4 transform = mat4("
+ " aScale.x, 0.0, 0.0, 0.0,"
+ " 0.0, aScale.y, 0.0, 0.0,"
+ " 0.0, 0.0, aScale.z, 0.0,"
+ " trans.x, trans.y, trans.z, 1.0"
+ " );"
+ " _vert_position = (transform * vec4(vPosition, 1.0)).xyz;"
+ " _vert_normal = irisNormals[int(floor(float(gl_VertexID) / 4.0))];"
+ " float blockLight = (float(uBlockLight) + 0.5) / 16.0;"
+ " float skyLight = (float(uSkyLight) + 0.5) / 16.0;"
+ " _vert_tex_light_coord = vec2(blockLight, skyLight);"
+ " dhMaterialId = aMaterial;"
+ " _vert_color = iris_color;"
+ " }"
);
transformer.prependMain("_vert_init();");
}
private static void addIfNotExists(Transformer transformer, String name, String code) {
if (!transformer.hasVariable(name)) {
transformer.injectVariable(code);
}
}
private static void replaceGlMultiTexCoordBounded(Transformer transformer, int from, int to) {
for (int i = from; i <= to; i++) {
transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)");
}
}
}
@@ -0,0 +1,106 @@
package net.coderbot.iris.pipeline.transform;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import org.taumc.glsl.Transformer;
public class DHTerrainTransformer {
public static void transform(Transformer transformer, Parameters parameters, int glslVersion) {
CommonTransformer.transform(transformer, parameters, true, glslVersion);
transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)");
transformer.replaceExpression("gl_TextureMatrix[1]", "mat4(1.0)");
transformer.rename("gl_ProjectionMatrix", "iris_ProjectionMatrix");
if (parameters.type == ShaderType.VERTEX) {
// Alias of gl_MultiTexCoord1 on 1.15+ for OptiFine
// See https://github.com/IrisShaders/Iris/issues/1149
transformer.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1");
transformer.replaceExpression("gl_MultiTexCoord0", "vec4(0.0, 0.0, 0.0, 1.0)");
transformer.replaceExpression("gl_MultiTexCoord1", "vec4(_vert_tex_light_coord, 0.0, 1.0)");
replaceGlMultiTexCoordBounded(transformer, 4, 7);
}
transformer.rename("gl_Color", "_vert_color");
if (parameters.type == ShaderType.VERTEX) {
transformer.replaceExpression("gl_Normal", "_vert_normal");
}
transformer.replaceExpression("gl_NormalMatrix", "iris_NormalMatrix");
addIfNotExists(transformer, "iris_NormalMatrix", "uniform mat3 iris_NormalMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrixInverse", "uniform mat4 iris_ModelViewMatrixInverse;");
addIfNotExists(transformer, "iris_ProjectionMatrixInverse", "uniform mat4 iris_ProjectionMatrixInverse;");
transformer.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix");
transformer.rename("gl_ModelViewMatrixInverse", "iris_ModelViewMatrixInverse");
transformer.rename("gl_ProjectionMatrixInverse", "iris_ProjectionMatrixInverse");
if (parameters.type == ShaderType.VERTEX) {
if (transformer.containsCall("ftransform")) {
transformer.injectFunction("vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }");
}
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
transformer.injectFunction("vec4 getVertexPosition() { return vec4(modelOffset + _vert_position, 1.0); }");
transformer.replaceExpression("gl_Vertex", "getVertexPosition()");
injectVertInit(transformer);
} else {
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
}
transformer.replaceExpression("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)");
ShaderTransformer.applyIntelHd4000Workaround(transformer);
}
public static void injectVertInit(Transformer transformer) {
addIfNotExists(transformer, "_vert_position", "vec3 _vert_position;");
addIfNotExists(transformer, "_vert_tex_light_coord", "vec2 _vert_tex_light_coord;");
addIfNotExists(transformer, "dhMaterialId", "int dhMaterialId;");
addIfNotExists(transformer, "_vert_color", "vec4 _vert_color;");
addIfNotExists(transformer, "_vert_normal", "vec3 _vert_normal;");
addIfNotExists(transformer, "mircoOffset", "uniform float mircoOffset;");
addIfNotExists(transformer, "modelOffset", "uniform vec3 modelOffset;");
addIfNotExists(transformer, "iris_color", "in vec4 iris_color;");
addIfNotExists(transformer, "vPosition", "in uvec4 vPosition;");
addIfNotExists(transformer, "irisExtra", "in uvec4 irisExtra;");
transformer.injectFunction("const vec3 irisNormals[6] = vec3[](vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1), vec3(-1,0,0), vec3(1,0,0));");
transformer.injectFunction(
"void _vert_init() {"
+ " uint meta = vPosition.a;"
+ " uint mirco = (meta & 0xFF00u) >> 8u;"
+ " float mx = (mirco & 1u) != 0u ? mircoOffset : 0.0;"
+ " mx = (mirco & 2u) != 0u ? -mx : mx;"
+ " float my = (mirco & 4u) != 0u ? mircoOffset : 0.0;"
+ " my = (mirco & 8u) != 0u ? -my : my;"
+ " float mz = (mirco & 16u) != 0u ? mircoOffset : 0.0;"
+ " mz = (mirco & 32u) != 0u ? -mz : mz;"
+ " uint lights = meta & 0xFFu;"
+ " _vert_position = (vPosition.xyz + vec3(mx, my, mz));"
+ " _vert_normal = irisNormals[int(irisExtra.y)];"
+ " dhMaterialId = int(irisExtra.x);"
+ " _vert_tex_light_coord = vec2((float(lights / 16u) + 0.5) / 16.0, (mod(float(lights), 16.0) + 0.5) / 16.0);"
+ " _vert_color = iris_color;"
+ " }"
);
transformer.prependMain("_vert_init();");
}
private static void addIfNotExists(Transformer transformer, String name, String code) {
if (!transformer.hasVariable(name)) {
transformer.injectVariable(code);
}
}
private static void replaceGlMultiTexCoordBounded(Transformer transformer, int from, int to) {
for (int i = from; i <= to; i++) {
transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)");
}
}
}
@@ -4,5 +4,7 @@ public enum Patch {
ATTRIBUTES,
CELERITAS_TERRAIN,
COMPOSITE,
COMPUTE
COMPUTE,
DH_TERRAIN,
DH_GENERIC
}
@@ -439,9 +439,16 @@ public class ShaderTransformer {
case COMPUTE:
ComputeTransformer.transform(transformer, parameters, versionInt);
break;
case DH_TERRAIN:
DHTerrainTransformer.transform(transformer, parameters, versionInt);
break;
case DH_GENERIC:
DHGenericTransformer.transform(transformer, parameters, versionInt);
break;
default:
throw new IllegalStateException("Unknown patch type: " + patchType.name());
}
TextureTransformer.transform(transformer, parameters);
CompatibilityTransformer.transformEach(transformer, parameters);
}
@@ -0,0 +1,51 @@
package net.coderbot.iris.pipeline.transform;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import net.coderbot.iris.gl.texture.TextureType;
import net.coderbot.iris.helpers.Tri;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import net.coderbot.iris.shaderpack.texture.TextureStage;
import org.taumc.glsl.Transformer;
import org.taumc.glsl.grammar.GLSLLexer;
final class TextureTransformer {
private TextureTransformer() {
}
static void transform(Transformer transformer, Parameters parameters) {
final Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap = parameters.getTextureMap();
if (textureMap == null || textureMap.isEmpty()) {
return;
}
final TextureStage stage = parameters.getTextureStage();
textureMap.forEach((key, replacement) -> {
if (key.third() != stage) {
return;
}
final String name = key.first();
final int type = transformer.findType(name);
if (type != 0 && isTypeValid(key.second(), type)) {
transformer.rename(name, replacement);
}
});
}
private static boolean isTypeValid(TextureType expectedType, int extractedType) {
return switch (expectedType) {
case TEXTURE_1D -> extractedType == GLSLLexer.SAMPLER1D ||
extractedType == GLSLLexer.ISAMPLER1D ||
extractedType == GLSLLexer.USAMPLER1D;
case TEXTURE_RECTANGLE -> extractedType == GLSLLexer.SAMPLER2DRECT ||
extractedType == GLSLLexer.ISAMPLER2DRECT ||
extractedType == GLSLLexer.USAMPLER2DRECT;
case TEXTURE_2D -> extractedType == GLSLLexer.SAMPLER2D ||
extractedType == GLSLLexer.ISAMPLER2D ||
extractedType == GLSLLexer.USAMPLER2D;
case TEXTURE_3D -> extractedType == GLSLLexer.SAMPLER3D ||
extractedType == GLSLLexer.ISAMPLER3D ||
extractedType == GLSLLexer.USAMPLER3D;
};
}
}
@@ -7,6 +7,7 @@ import net.coderbot.iris.helpers.Tri;
import net.coderbot.iris.pipeline.transform.parameter.AttributeParameters;
import net.coderbot.iris.pipeline.transform.parameter.CeleritasTerrainParameters;
import net.coderbot.iris.pipeline.transform.parameter.ComputeParameters;
import net.coderbot.iris.pipeline.transform.parameter.DHParameters;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import net.coderbot.iris.pipeline.transform.parameter.TextureStageParameters;
import net.coderbot.iris.shaderpack.texture.TextureStage;
@@ -119,14 +120,27 @@ public class TransformPatcher {
return patchComposite(vertex, geometry, null, null, fragment, TextureStage.COMPOSITE_AND_FINAL, null);
}
public static Map<PatchShaderType, String> patchComposite(String vertex, String geometry, String tessControl, String tessEval, String fragment) {
return patchComposite(vertex, geometry, tessControl, tessEval, fragment, TextureStage.COMPOSITE_AND_FINAL, null);
}
public static Map<PatchShaderType, String> patchComposite(String vertex, String geometry, String tessControl, String tessEval, String fragment, TextureStage stage, Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return transform(vertex, geometry, tessControl, tessEval, fragment, new TextureStageParameters(Patch.COMPOSITE, stage, textureMap));
}
public static Map<PatchShaderType, String> patchDHTerrain(
String name, String vertex, String tessControl, String tessEval, String geometry, String fragment,
Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return transform(vertex, geometry, tessControl, tessEval, fragment,
new DHParameters(Patch.DH_TERRAIN, textureMap));
}
public static Map<PatchShaderType, String> patchDHGeneric(
String name, String vertex, String tessControl, String tessEval, String geometry, String fragment,
Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return transform(vertex, geometry, tessControl, tessEval, fragment,
new DHParameters(Patch.DH_GENERIC, textureMap));
}
public static Map<PatchShaderType, String> patchComposite(String vertex, String geometry, String fragment, TextureStage stage, Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return patchComposite(vertex, geometry, null, null, fragment, stage, textureMap);
}
@@ -0,0 +1,18 @@
package net.coderbot.iris.pipeline.transform.parameter;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import net.coderbot.iris.gl.texture.TextureType;
import net.coderbot.iris.helpers.Tri;
import net.coderbot.iris.pipeline.transform.Patch;
import net.coderbot.iris.shaderpack.texture.TextureStage;
public class DHParameters extends Parameters {
public DHParameters(Patch patch, Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
super(patch, textureMap);
}
@Override
public TextureStage getTextureStage() {
return TextureStage.GBUFFERS_AND_SHADOW;
}
}
@@ -146,7 +146,7 @@ public class FinalPassRenderer {
GLStateManager.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, 0);
}
private static Map<PatchShaderType, String> getTransformed(ProgramSource source, CompletableFuture<Map<PatchShaderType, String>> precomputedTransformFuture, String stageName) {
private Map<PatchShaderType, String> getTransformed(ProgramSource source, CompletableFuture<Map<PatchShaderType, String>> precomputedTransformFuture, String stageName) {
if (precomputedTransformFuture != null) {
try {
final Map<PatchShaderType, String> result = precomputedTransformFuture.join();
@@ -157,7 +157,14 @@ public class FinalPassRenderer {
throw new RuntimeException("Shader transformation failed for '" + source.getName() + "' in stage '" + stageName + "'", e.getCause() != null ? e.getCause() : e);
}
}
return TransformPatcher.patchComposite(source.getVertexSource().orElseThrow(NullPointerException::new), source.getGeometrySource().orElse(null), source.getTessControlSource().orElse(null), source.getTessEvalSource().orElse(null), source.getFragmentSource().orElseThrow(NullPointerException::new));
return TransformPatcher.patchComposite(
source.getVertexSource().orElseThrow(NullPointerException::new),
source.getGeometrySource().orElse(null),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getFragmentSource().orElseThrow(NullPointerException::new),
TextureStage.COMPOSITE_AND_FINAL,
pipeline != null ? pipeline.getTextureMap() : null);
}
private static final class Pass {
@@ -248,6 +248,16 @@ public class RenderTargets {
return framebuffer;
}
public GlFramebuffer createDHFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
}
ImmutableSet<Integer> stageWritesToMain = invert(stageWritesToAlt, drawBuffers);
return createColorFramebuffer(stageWritesToMain, drawBuffers);
}
public GlFramebuffer createGbufferFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
@@ -28,7 +28,7 @@ public class PackDirectives {
@Getter private float eyeBrightnessHalfLife;
@Getter private float centerDepthHalfLife;
@Getter private CloudSetting cloudSetting;
@Getter private CloudSetting dhCloudSetting;
private CloudSetting dhCloudSetting;
private boolean underwaterOverlay;
private boolean vignette;
private boolean sun;
@@ -181,6 +181,10 @@ public class PackDirectives {
return concurrentCompute;
}
public CloudSetting getDHCloudSetting() {
return dhCloudSetting;
}
private static float clamp(float val, float lo, float hi) {
return Math.max(lo, Math.min(hi, val));
}
@@ -30,6 +30,8 @@ public class PackShadowDirectives {
private final boolean shouldRenderPlayer;
private final boolean shouldRenderBlockEntities;
@Getter private final ShadowCullState cullingState;
private final OptionalBoolean dhShadowEnabled;
private float nearPlane, farPlane;
private final ImmutableList<DepthSamplingSettings> depthSamplingSettings;
private final ImmutableList<SamplingSettings> colorSamplingSettings;
@@ -53,6 +55,8 @@ public class PackShadowDirectives {
// shadowRenderDistanceMul to a nonzero value, since having a high shadow render distance will impact
// performance quite heavily on most systems.
this.distance = 160.0f;
this.nearPlane = 0.05f;
this.farPlane = 256.0f;
this.voxelDistance = 0.0f;
// By default, shadows are not culled based on distance from the player. However, pack authors may
@@ -81,6 +85,7 @@ public class PackShadowDirectives {
this.shouldRenderBlockEntities = properties.getShadowBlockEntities().orElse(true);
this.cullingState = properties.getShadowCulling();
this.shadowEnabled = properties.getShadowEnabled();
this.dhShadowEnabled = properties.getDhShadowEnabled();
this.depthSamplingSettings = ImmutableList.of(new DepthSamplingSettings(), new DepthSamplingSettings());
@@ -97,6 +102,8 @@ public class PackShadowDirectives {
this.resolution = shadowDirectives.resolution;
this.fov = shadowDirectives.fov;
this.distance = shadowDirectives.distance;
this.nearPlane = shadowDirectives.nearPlane;
this.farPlane = shadowDirectives.farPlane;
this.voxelDistance = shadowDirectives.voxelDistance;
this.distanceRenderMul = shadowDirectives.distanceRenderMul;
this.entityShadowDistanceMul = shadowDirectives.entityShadowDistanceMul;
@@ -111,6 +118,7 @@ public class PackShadowDirectives {
this.depthSamplingSettings = shadowDirectives.depthSamplingSettings;
this.colorSamplingSettings = shadowDirectives.colorSamplingSettings;
this.shadowEnabled = shadowDirectives.shadowEnabled;
this.dhShadowEnabled = shadowDirectives.dhShadowEnabled;
}
public int getResolution() {
@@ -125,6 +133,18 @@ public class PackShadowDirectives {
return distance;
}
public float getNearPlane() {
return nearPlane;
}
public float getFarPlane() {
return farPlane;
}
public OptionalBoolean isDhShadowEnabled() {
return dhShadowEnabled;
}
public float getVoxelDistance() {
return voxelDistance;
}
@@ -186,7 +206,8 @@ public class PackShadowDirectives {
directives.acceptCommentFloatDirective("SHADOWHPL", distance -> this.distance = distance);
directives.acceptConstFloatDirective("shadowDistance", distance -> this.distance = distance);
directives.acceptConstFloatDirective("shadowNearPlane", nearPlane -> this.nearPlane = nearPlane);
directives.acceptConstFloatDirective("shadowFarPlane", farPlane -> this.farPlane = farPlane);
directives.acceptConstFloatDirective("entityShadowDistanceMul", distance -> this.entityShadowDistanceMul = distance);
directives.acceptConstFloatDirective("shadowDistanceRenderMul", distanceRenderMul -> {
@@ -56,7 +56,10 @@ public class ProgramSet {
private final ComputeSource[][] compositeCompute;
private final ProgramSource compositeFinal;
private final ComputeSource[] finalCompute;
private final ProgramSource dhTerrain;
private final ProgramSource dhGeneric;
private final ProgramSource dhWater;
private final ProgramSource dhShadow;
private final ShaderPack pack;
@@ -119,6 +122,10 @@ public class ProgramSet {
this.gbuffersBlock = readProgramSource(directory, sourceProvider, "gbuffers_block", this, shaderProperties);
this.gbuffersBlockTrans = readProgramSource(directory, sourceProvider, "gbuffers_block_translucent", this, shaderProperties);
this.gbuffersHand = readProgramSource(directory, sourceProvider, "gbuffers_hand", this, shaderProperties);
this.dhTerrain = readProgramSource(directory, sourceProvider, "dh_terrain", this, shaderProperties);
this.dhGeneric = readProgramSource(directory, sourceProvider, "dh_generic", this, shaderProperties);
this.dhWater = readProgramSource(directory, sourceProvider, "dh_water", this, shaderProperties);
this.dhShadow = readProgramSource(directory, sourceProvider, "dh_shadow", this, shaderProperties);
this.deferred = readProgramArray(directory, sourceProvider, "deferred", shaderProperties);
this.deferredCompute = new ComputeSource[deferred.length][];
@@ -219,7 +226,7 @@ public class ProgramSet {
gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain,
gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather,
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans,
gbuffersHand
gbuffersHand, dhShadow, dhTerrain, dhGeneric, dhWater
));
for (ComputeSource[] computeSources : compositeCompute) {
@@ -387,33 +394,53 @@ public class ProgramSet {
return gbuffersHand.requireValid();
}
public Optional<ProgramSource> getDhTerrain() {
return dhTerrain.requireValid();
}
public Optional<ProgramSource> getDhGeneric() {
return dhGeneric.requireValid();
}
public Optional<ProgramSource> getDhWater() {
return dhWater.requireValid();
}
public Optional<ProgramSource> getDhShadow() {
return dhShadow.requireValid();
}
public Optional<ProgramSource> get(ProgramId programId) {
return switch (programId) {
case Shadow -> getShadow();
case Basic -> getGbuffersBasic();
case Line -> gbuffersLine.requireValid();
case Textured -> getGbuffersTextured();
case TexturedLit -> getGbuffersTexturedLit();
case SkyBasic -> getGbuffersSkyBasic();
case SkyTextured -> getGbuffersSkyTextured();
case Clouds -> getGbuffersClouds();
case Terrain -> getGbuffersTerrain();
case DamagedBlock -> getGbuffersDamagedBlock();
case Block -> getGbuffersBlock();
return switch (programId) {
case Shadow -> getShadow();
case Basic -> getGbuffersBasic();
case Line -> gbuffersLine.requireValid();
case Textured -> getGbuffersTextured();
case TexturedLit -> getGbuffersTexturedLit();
case SkyBasic -> getGbuffersSkyBasic();
case SkyTextured -> getGbuffersSkyTextured();
case Clouds -> getGbuffersClouds();
case Terrain -> getGbuffersTerrain();
case DamagedBlock -> getGbuffersDamagedBlock();
case Block -> getGbuffersBlock();
case BlockTrans -> getGbuffersBlockTrans();
case BeaconBeam -> getGbuffersBeaconBeam();
case Entities -> getGbuffersEntities();
case EntitiesTrans -> getGbuffersEntitiesTrans();
case EntitiesGlowing -> getGbuffersEntitiesGlowing();
case ArmorGlint -> getGbuffersGlint();
case SpiderEyes -> getGbuffersEntityEyes();
case Hand -> getGbuffersHand();
case Weather -> getGbuffersWeather();
case Water -> getGbuffersWater();
case HandWater -> getGbuffersHandWater();
case Final -> getCompositeFinal();
default -> Optional.empty();
};
case BeaconBeam -> getGbuffersBeaconBeam();
case Entities -> getGbuffersEntities();
case EntitiesTrans -> getGbuffersEntitiesTrans();
case EntitiesGlowing -> getGbuffersEntitiesGlowing();
case ArmorGlint -> getGbuffersGlint();
case SpiderEyes -> getGbuffersEntityEyes();
case Hand -> getGbuffersHand();
case Weather -> getGbuffersWeather();
case Water -> getGbuffersWater();
case HandWater -> getGbuffersHandWater();
case Final -> getCompositeFinal();
case DhTerrain -> getDhTerrain();
case DhGeneric -> getDhGeneric();
case DhWater -> getDhWater();
case DhShadow -> getDhShadow();
default -> Optional.empty();
};
}
public ProgramSource[] getDeferred() {
@@ -495,15 +495,15 @@ public class ShaderProperties {
customUniforms.addVariable(parts[0], parts[1], value, false);
});
handlePassDirective("uniform.", key, value, pass -> {
String[] parts = pass.split("\\.");
if (parts.length != 2) {
Iris.logger.warn("Custom uniforms sould take the form of `uniform.<type>.<name> = <expression>. Ignoring " + key);
return;
}
handlePassDirective("uniform.", key, value, pass -> {
String[] parts = pass.split("\\.");
if (parts.length != 2) {
Iris.logger.warn("Custom uniforms sould take the form of `uniform.<type>.<name> = <expression>. Ignoring " + key);
return;
}
customUniforms.addVariable(parts[0], parts[1], value, true);
});
customUniforms.addVariable(parts[0], parts[1], value, true);
});
// TODO: Buffer size directives
// TODO: Conditional program enabling directives
@@ -7,7 +7,8 @@ public enum ProgramGroup {
Gbuffers("gbuffers"),
Deferred("deferred"),
Composite("composite"),
Final("final")
Final("final"),
Dh("dh")
;
private final String baseName;
@@ -47,6 +47,10 @@ public enum ProgramId {
Weather(ProgramGroup.Gbuffers, "weather", TexturedLit),
Water(ProgramGroup.Gbuffers, "water", Terrain),
HandWater(ProgramGroup.Gbuffers, "hand_water", Hand),
DhTerrain(ProgramGroup.Dh, "terrain"),
DhWater(ProgramGroup.Dh, "water", DhTerrain),
DhGeneric(ProgramGroup.Dh, "generic", DhTerrain),
DhShadow(ProgramGroup.Dh, "shadow"),
Final(ProgramGroup.Final, ""),
;
@@ -11,16 +11,16 @@ public class ShadowMatrices {
// NB: These matrices are in column-major order, not row-major order like what you'd expect!
public static Matrix4f createOrthoMatrix(float halfPlaneLength) {
public static Matrix4f createOrthoMatrix(float halfPlaneLength, float nearPlane, float farPlane) {
return new Matrix4f(
// column 1
1.0f / halfPlaneLength, 0f, 0f, 0f,
// column 2
0f, 1.0f / halfPlaneLength, 0f, 0f,
// column 3
0f, 0f, 2.0f / (NEAR - FAR), 0f,
0f, 0f, 2.0f / (nearPlane - farPlane), 0f,
// column 4
0f, 0f, -(FAR + NEAR) / (FAR - NEAR), 1f
0f, 0f, -(farPlane + nearPlane) / (farPlane - nearPlane), 1f
);
}
@@ -104,7 +104,7 @@ public class ShadowMatrices {
0f, 0f, -1.000390648841858f, 1f
);
test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f));
test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f, 0.05f, 256.0f));
// const float shadowDistance = 110.0;
// /* SHADOWHPL:110.0 */
@@ -115,7 +115,7 @@ public class ShadowMatrices {
0, 0, -1.000390648841858f, 1
);
test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f));
test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f, 0.05f, 256.0f));
Matrix4f expected90Proj = new Matrix4f(
1.0f, 0.0f, 0.0f, 0.0f,
@@ -263,7 +263,9 @@ public class ShadowCompositeRenderer {
source.getGeometrySource().orElse(null),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getFragmentSource().orElseThrow(NullPointerException::new));
source.getFragmentSource().orElseThrow(NullPointerException::new),
TextureStage.SHADOWCOMP,
pipeline.getTextureMap());
String vertex = transformed.get(PatchShaderType.VERTEX);
String geometry = transformed.get(PatchShaderType.GEOMETRY);
String tessControl = transformed.get(PatchShaderType.TESS_CONTROL);
@@ -206,6 +206,20 @@ public class ShadowRenderTargets {
return framebuffer;
}
public GlFramebuffer createDHFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
}
ImmutableSet<Integer> stageWritesToMain = invert(stageWritesToAlt, drawBuffers);
GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers);
framebuffer.addDepthAttachment(mainDepth.getTextureId());
return framebuffer;
}
public GlFramebuffer createShadowFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
import org.embeddedt.embeddium.impl.render.viewport.Viewport;
@@ -7,7 +10,8 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Vector3d;
public class CullEverythingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class CullEverythingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private final Vector3d position = new Vector3d();
@Override
@@ -24,4 +28,16 @@ public class CullEverythingFrustum extends Frustrum implements ViewportProvider,
public Viewport sodium$createViewport() {
return new Viewport(this, position.set(xPosition, yPosition, zPosition));
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return false;
}
}
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum.advanced;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.coderbot.iris.shadows.frustum.BoxCuller;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
@@ -8,6 +11,7 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Math;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
@@ -32,7 +36,8 @@ import org.joml.Vector4f;
* are not sensitive to the specific internal ordering of planes and corners, in order to avoid potential bugs at the
* cost of slightly more computations.</p>
*/
public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private static final int MAX_CLIPPING_PLANES = 13;
/**
@@ -79,6 +84,8 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr
private final BaseClippingPlanes baseClippingPlanes = new BaseClippingPlanes();
private final boolean[] isBackArray = new boolean[6];
private int worldMinYDH;
private int worldMaxYDH;
public AdvancedShadowCullingFrustum() {
for (int i = 0; i < MAX_CLIPPING_PLANES; i++) {
@@ -86,7 +93,7 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr
}
}
public void init(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVector, BoxCuller boxCuller) {
public void init(Matrix4fc playerView, Matrix4fc playerProjection, Vector3f shadowLightVector, BoxCuller boxCuller) {
this.shadowLightVectorFromOrigin.set(shadowLightVector);
this.boxCuller = boxCuller;
this.planeCount = 0;
@@ -298,4 +305,17 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr
return true;
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
this.worldMinYDH = worldMinBlockY;
this.worldMaxYDH = worldMaxBlockY;
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return this.isVisible(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth);
}
}
@@ -1,6 +1,7 @@
package net.coderbot.iris.shadows.frustum.advanced;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector4f;
public class BaseClippingPlanes {
@@ -13,7 +14,7 @@ public class BaseClippingPlanes {
}
}
public void init(Matrix4f view, Matrix4f projection) {
public void init(Matrix4fc view, Matrix4fc projection) {
// Transform = Transpose(Projection x View)
transformScratch.set(projection);
transformScratch.mul(view);
@@ -3,12 +3,13 @@ package net.coderbot.iris.shadows.frustum.advanced;
import net.coderbot.iris.shadows.frustum.BoxCuller;
import net.minecraft.util.AxisAlignedBB;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3f;
public class SafeZoneCullingFrustum extends AdvancedShadowCullingFrustum {
private final BoxCuller distanceCuller;
public SafeZoneCullingFrustum(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVector, BoxCuller voxelCuller, BoxCuller distanceCuller) {
public SafeZoneCullingFrustum(Matrix4fc playerView, Matrix4fc playerProjection, Vector3f shadowLightVector, BoxCuller voxelCuller, BoxCuller distanceCuller) {
super();
init(playerView, playerProjection, shadowLightVector, voxelCuller);
this.distanceCuller = distanceCuller;
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum.fallback;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.coderbot.iris.shadows.frustum.BoxCuller;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
@@ -8,9 +11,12 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Vector3d;
public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private final BoxCuller boxCuller;
private final Vector3d position = new Vector3d();
private int worldMinYDH;
private int worldMaxYDH;
public BoxCullingFrustum(BoxCuller boxCuller) {
this.boxCuller = boxCuller;
@@ -36,4 +42,17 @@ public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Fru
public Viewport sodium$createViewport() {
return new Viewport(this, position.set(xPosition, yPosition, zPosition));
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
this.worldMinYDH = worldMinBlockY;
this.worldMaxYDH = worldMaxBlockY;
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return !boxCuller.isCulled(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth);
}
}
Loaded 100 of 141 files, more files were not shown because too many files have changed in this diff. Show more