mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 09:44:52 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54c99386d4 | ||
|
|
465abf889a | ||
|
|
4acb83be6a | ||
|
|
80f9724ee6 | ||
|
|
8cf55bb216 | ||
|
|
3ebc8868c7 | ||
|
|
0938e6d975 | ||
|
|
d3022a40d2 | ||
|
|
2645c803f9 | ||
|
|
d91c356a99 | ||
|
|
189ff4a80f | ||
|
|
ffb4ca9472 | ||
|
|
7d8c8d306d | ||
|
|
117ff0cacf | ||
|
|
83fdd57534 | ||
|
|
951be04e9a |
No files matched your search
+1
-1
@@ -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")
|
||||
|
||||
@@ -345,6 +345,17 @@ public class FeedbackManager {
|
||||
}
|
||||
break;
|
||||
|
||||
case GL11.GL_QUAD_STRIP:
|
||||
for (int i = 0; i + 3 < count; i += 2) {
|
||||
feedbackToken(GL11.GL_POLYGON_TOKEN);
|
||||
feedbackToken(4);
|
||||
emitVertex(reader.read(i), stride);
|
||||
emitVertex(reader.read(i + 1), stride);
|
||||
emitVertex(reader.read(i + 3), stride);
|
||||
emitVertex(reader.read(i + 2), stride);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL11.GL_POLYGON:
|
||||
if (count >= 3) {
|
||||
feedbackToken(GL11.GL_POLYGON_TOKEN);
|
||||
|
||||
@@ -2341,6 +2341,8 @@ public class GLStateManager {
|
||||
prepareClientArrays();
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadsAsTriangles(first, count);
|
||||
} else if (mode == GL11.GL_QUAD_STRIP) {
|
||||
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_STRIP, first, count & ~1);
|
||||
} else if (mode == GL11.GL_POLYGON) {
|
||||
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_FAN, first, count);
|
||||
} else {
|
||||
@@ -2361,6 +2363,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);
|
||||
}
|
||||
@@ -2402,6 +2408,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);
|
||||
}
|
||||
@@ -2418,6 +2428,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);
|
||||
}
|
||||
@@ -2440,6 +2454,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;
|
||||
@@ -2458,6 +2476,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;
|
||||
@@ -2504,32 +2528,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) {
|
||||
@@ -2538,20 +2553,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); }
|
||||
@@ -4360,9 +4370,20 @@ public class GLStateManager {
|
||||
RENDER_BACKEND.finish();
|
||||
}
|
||||
|
||||
public static int glGetError() { return RENDER_BACKEND.getError(); }
|
||||
public static String glGetString(int pname) { return RENDER_BACKEND.getString(pname); }
|
||||
public static String glGetStringi(int name, int index) { return RENDER_BACKEND.getStringi(name, index); }
|
||||
public static int glGetError() {
|
||||
if (!RENDER_BACKEND.hasContext()) return 0;
|
||||
return RENDER_BACKEND.getError();
|
||||
}
|
||||
|
||||
public static String glGetString(int pname) {
|
||||
if (!RENDER_BACKEND.hasContext()) return "no valid GL/render context";
|
||||
return RENDER_BACKEND.getString(pname);
|
||||
}
|
||||
|
||||
public static String glGetStringi(int name, int index) {
|
||||
if (!RENDER_BACKEND.hasContext()) return "no valid GL/render context";
|
||||
return RENDER_BACKEND.getStringi(name, index);
|
||||
}
|
||||
|
||||
public static void glShaderSource(int shader, CharSequence source) {
|
||||
String src = source.toString();
|
||||
|
||||
+11
-1
@@ -9,6 +9,7 @@ import org.lwjgl.opengl.ARBDebugOutputCallback;
|
||||
import org.lwjgl.opengl.ARBDirectStateAccess;
|
||||
import org.lwjgl.opengl.ContextCapabilities;
|
||||
import org.lwjgl.opengl.EXTDirectStateAccess;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
@@ -67,7 +68,7 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
caps = org.lwjgl.opengl.GLContext.getCapabilities();
|
||||
caps = GLContext.getCapabilities();
|
||||
activeDebugExtension = 0;
|
||||
}
|
||||
|
||||
@@ -86,6 +87,15 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
return "OpenGL (LWJGL2)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContext() {
|
||||
try {
|
||||
return GLContext.getCapabilities() != null;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinGLSLVersion() {return 330;}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ public abstract class RenderBackend {
|
||||
public abstract boolean isAvailable();
|
||||
public abstract String getName();
|
||||
|
||||
/** Returns true if the current thread has a valid render context. Safe to call from any thread. */
|
||||
public abstract boolean hasContext();
|
||||
|
||||
/** Higher priority backends are preferred. */
|
||||
public int getPriority() { return 0; }
|
||||
|
||||
|
||||
+3
@@ -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_QUAD_STRIP) {
|
||||
// GL_QUAD_STRIP is removed in core profile; an even-length GL_TRIANGLE_STRIP produces the same quads
|
||||
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(vao, GL11.GL_TRIANGLE_STRIP, start, vertexCount & ~1);
|
||||
} 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);
|
||||
|
||||
@@ -207,6 +207,57 @@ class FeedbackManagerTest {
|
||||
GLStateManager.glDeleteVertexArrays(vao);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testQuadStripFeedback_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,
|
||||
0f, 1f, 0f,
|
||||
1f, 0f, 0f,
|
||||
1f, 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_QUAD_STRIP, 0, 4);
|
||||
|
||||
final int count = FeedbackManager.glRenderMode(GL11.GL_RENDER);
|
||||
|
||||
assertEquals(10, count, "Quad strip 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(400.0f, buf.get(4), 0.01f);
|
||||
assertEquals(600.0f, buf.get(5), 0.01f);
|
||||
assertEquals(800.0f, buf.get(6), 0.01f);
|
||||
assertEquals(600.0f, buf.get(7), 0.01f);
|
||||
assertEquals(800.0f, buf.get(8), 0.01f);
|
||||
assertEquals(300.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);
|
||||
|
||||
+10
@@ -68,6 +68,16 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
return "OpenGL (LWJGL3)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContext() {
|
||||
try {
|
||||
GL.getCapabilities();
|
||||
return true;
|
||||
} catch (IllegalStateException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() { return 50; }
|
||||
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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,6 +11,7 @@ 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;
|
||||
@@ -17,7 +19,21 @@ 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() {
|
||||
@@ -75,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);
|
||||
|
||||
@@ -152,6 +152,7 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
|
||||
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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -37,9 +37,13 @@ public enum Mixins implements IMixins {
|
||||
, "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"
|
||||
@@ -240,6 +244,7 @@ public enum Mixins implements IMixins {
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins(
|
||||
"shaders.MixinDroppedItemGlintEdges"
|
||||
, "shaders.MixinHeldItemGlintEdges"
|
||||
, "shaders.MixinEntityPickupFX"
|
||||
, "shaders.MixinEntityRenderer"
|
||||
, "shaders.MixinGuiIngameForge"
|
||||
@@ -252,6 +257,7 @@ public enum Mixins implements IMixins {
|
||||
, "shaders.MixinRenderEntityFlame"
|
||||
, "shaders.MixinRendererLivingEntity"
|
||||
, "shaders.MixinRenderGlobal"
|
||||
, "shaders.AccessorEntityHorse"
|
||||
, "shaders.MixinRenderHorse"
|
||||
, "shaders.MixinRenderItem"
|
||||
, "shaders.MixinRenderNameTag"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -85,6 +86,7 @@ public final class ClientProxy extends CommonProxy {
|
||||
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) {
|
||||
@@ -182,6 +184,9 @@ public final 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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-8
@@ -79,13 +79,13 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
|
||||
baseEncoder.write(ptr, material, vertex, sectionIndex);
|
||||
|
||||
// Per-vertex: renderType, midBlock, lightValue
|
||||
memPutShort(ptr + MC_ENTITY_OFFSET + 2, ctx.renderType);
|
||||
// Per-vertex: mc_Entity (packed blockId + renderType), midBlock, lightValue
|
||||
memPutInt(ptr + MC_ENTITY_OFFSET, ((ctx.blockId + 1) << 1) | (ctx.renderType & 1));
|
||||
final int midBlock = ExtendedDataHelper.computeMidBlock(vertex.x, vertex.y, vertex.z, ctx.localPosX, ctx.localPosY, ctx.localPosZ);
|
||||
memPutInt(ptr + MID_BLOCK_OFFSET, midBlock);
|
||||
memPutByte(ptr + MID_BLOCK_OFFSET + 3, ctx.lightValue);
|
||||
|
||||
// Per-quad: midTexCoord, blockId, normal, tangent
|
||||
// Per-quad: midTexCoord, normal, tangent
|
||||
if (vertexCount == 4) {
|
||||
vertexCount = 0;
|
||||
|
||||
@@ -98,11 +98,6 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
memPutInt(ptr + MID_TEX_OFFSET - STRIDE * 2, midUV);
|
||||
memPutInt(ptr + MID_TEX_OFFSET - STRIDE * 3, midUV);
|
||||
|
||||
memPutShort(ptr + MC_ENTITY_OFFSET, ctx.blockId);
|
||||
memPutShort(ptr + MC_ENTITY_OFFSET - STRIDE, ctx.blockId);
|
||||
memPutShort(ptr + MC_ENTITY_OFFSET - STRIDE * 2, ctx.blockId);
|
||||
memPutShort(ptr + MC_ENTITY_OFFSET - STRIDE * 3, ctx.blockId);
|
||||
|
||||
quad.setup(ptr, STRIDE);
|
||||
NormalHelper.computeFaceNormal(normal, quad);
|
||||
final int packedNormal = NormI8.pack(normal);
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ import org.embeddedt.embeddium.impl.render.chunk.vertex.format.ChunkVertexType;
|
||||
* mc_midTexCoord ushort[2] - quad center UV (average of 4 vertices)
|
||||
* at_tangent byte[4] - tangent vector, normalized
|
||||
* iris_Normal byte[3]+1 - face normal, normalized
|
||||
* mc_Entity short[2] - (blockId, renderType)
|
||||
* mc_Entity uint - packed as ((blockId + 1) << 1) | (renderType & 1)
|
||||
* at_midBlock byte[4] - (xyz offset from block center, lightValue)
|
||||
*/
|
||||
public class IrisExtendedChunkVertexType implements ChunkVertexType {
|
||||
@@ -25,7 +25,7 @@ public class IrisExtendedChunkVertexType implements ChunkVertexType {
|
||||
.addElement("mc_midTexCoord", GlVertexFormat.NEXT_ALIGNED_POINTER, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false, false)
|
||||
.addElement("at_tangent", GlVertexFormat.NEXT_ALIGNED_POINTER, GlVertexAttributeFormat.BYTE, 4, true, false)
|
||||
.addElement("iris_Normal", GlVertexFormat.NEXT_ALIGNED_POINTER, GlVertexAttributeFormat.BYTE, 3, true, false)
|
||||
.addElement("mc_Entity", GlVertexFormat.NEXT_ALIGNED_POINTER, GlVertexAttributeFormat.SHORT, 2, false, false)
|
||||
.addElement("mc_Entity", GlVertexFormat.NEXT_ALIGNED_POINTER, GlVertexAttributeFormat.UNSIGNED_INT, 1, false, true)
|
||||
.addElement("at_midBlock", GlVertexFormat.NEXT_ALIGNED_POINTER, GlVertexAttributeFormat.BYTE, 4, false, false)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -72,9 +72,11 @@ public class CeleritasTerrainPipeline {
|
||||
Optional<ProgramSource> terrainSource,
|
||||
Optional<ProgramSource> translucentSource,
|
||||
Optional<ProgramSource> shadowSource,
|
||||
Optional<ProgramSource> shadowTranslucentSource,
|
||||
CompletableFuture<Map<PatchShaderType, String>> terrainFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> translucentFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> shadowFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> shadowTranslucentFuture,
|
||||
RenderTargets renderTargets,
|
||||
ImmutableSet<Integer> flippedAfterPrepare,
|
||||
ImmutableSet<Integer> flippedAfterTranslucent,
|
||||
@@ -92,6 +94,7 @@ public class CeleritasTerrainPipeline {
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_CUTOUT, terrainSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_TRANSLUCENT, translucentSource.isPresent() ? translucentSource : terrainSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW, shadowSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW_TRANSLUCENT, shadowTranslucentSource.isPresent() ? shadowTranslucentSource : shadowSource);
|
||||
|
||||
// Initialize PassInfo, framebuffers, blend modes, and alpha in single pass
|
||||
for (IrisTerrainPass pass : IrisTerrainPass.VALUES) {
|
||||
@@ -101,11 +104,12 @@ public class CeleritasTerrainPipeline {
|
||||
// Set up framebuffer, blend mode, and buffer blend overrides
|
||||
final ProgramId programId = switch (pass) {
|
||||
case GBUFFER_TRANSLUCENT -> ProgramId.Water;
|
||||
case SHADOW_TRANSLUCENT -> ProgramId.ShadowWater;
|
||||
case SHADOW, SHADOW_CUTOUT -> ProgramId.Shadow;
|
||||
default -> ProgramId.Terrain;
|
||||
};
|
||||
|
||||
if (pass == IrisTerrainPass.SHADOW || pass == IrisTerrainPass.SHADOW_CUTOUT) {
|
||||
if (pass.isShadow()) {
|
||||
passInfo.framebuffer = shadowFramebuffer;
|
||||
passInfo.blendModeOverride = programId.getBlendModeOverride();
|
||||
passInfo.bufferBlendOverrides = Collections.emptyList();
|
||||
@@ -145,6 +149,7 @@ public class CeleritasTerrainPipeline {
|
||||
processShaderFuture(terrainFuture, terrainSource, passInfoMap.get(IrisTerrainPass.GBUFFER_SOLID), passInfoMap.get(IrisTerrainPass.GBUFFER_CUTOUT));
|
||||
processShaderFuture(translucentFuture, translucentSource, passInfoMap.get(IrisTerrainPass.GBUFFER_TRANSLUCENT));
|
||||
processShaderFuture(shadowFuture, shadowSource, passInfoMap.get(IrisTerrainPass.SHADOW), passInfoMap.get(IrisTerrainPass.SHADOW_CUTOUT));
|
||||
processShaderFuture(shadowTranslucentFuture, shadowTranslucentSource.isPresent() ? shadowTranslucentSource : shadowSource, passInfoMap.get(IrisTerrainPass.SHADOW_TRANSLUCENT));
|
||||
}
|
||||
|
||||
private void processShaderFuture(@Nullable CompletableFuture<Map<PatchShaderType, String>> future, Optional<ProgramSource> source, PassInfo... targets) {
|
||||
|
||||
@@ -136,8 +136,10 @@ public class IrisCeleritasChunkProgramOverrides {
|
||||
if (celeritasPipeline != null && !celeritasPipeline.hasShadowPass()) {
|
||||
throw new IllegalStateException("Shadow program requested, but shader pack has no shadow pass");
|
||||
}
|
||||
return programs.get(pass.supportsFragmentDiscard() ?
|
||||
IrisTerrainPass.SHADOW_CUTOUT : IrisTerrainPass.SHADOW);
|
||||
if (pass.isReverseOrder()) {
|
||||
return programs.get(IrisTerrainPass.SHADOW_TRANSLUCENT);
|
||||
}
|
||||
return programs.get(pass.supportsFragmentDiscard() ? IrisTerrainPass.SHADOW_CUTOUT : IrisTerrainPass.SHADOW);
|
||||
} else {
|
||||
if (pass.supportsFragmentDiscard()) {
|
||||
return programs.get(IrisTerrainPass.GBUFFER_CUTOUT);
|
||||
|
||||
@@ -187,7 +187,11 @@ public class IrisCeleritasChunkShaderInterface implements ChunkShaderInterface {
|
||||
final boolean isShadow = ShadowRenderingState.areShadowsCurrentlyBeingRendered();
|
||||
final IrisTerrainPass irisPass;
|
||||
if (isShadow) {
|
||||
irisPass = pass.supportsFragmentDiscard() ? IrisTerrainPass.SHADOW_CUTOUT : IrisTerrainPass.SHADOW;
|
||||
if (pass.isReverseOrder()) {
|
||||
irisPass = IrisTerrainPass.SHADOW_TRANSLUCENT;
|
||||
} else {
|
||||
irisPass = pass.supportsFragmentDiscard() ? IrisTerrainPass.SHADOW_CUTOUT : IrisTerrainPass.SHADOW;
|
||||
}
|
||||
} else if (pass.isReverseOrder()) {
|
||||
irisPass = IrisTerrainPass.GBUFFER_TRANSLUCENT;
|
||||
} else if (pass.supportsFragmentDiscard()) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.embeddedt.embeddium.impl.render.chunk.terrain.TerrainRenderPass;
|
||||
public enum IrisTerrainPass {
|
||||
SHADOW("shadow"),
|
||||
SHADOW_CUTOUT("shadow"),
|
||||
SHADOW_TRANSLUCENT("shadow_water"),
|
||||
GBUFFER_SOLID("gbuffers_terrain"),
|
||||
GBUFFER_CUTOUT("gbuffers_terrain_cutout"),
|
||||
GBUFFER_TRANSLUCENT("gbuffers_water");
|
||||
@@ -23,19 +24,22 @@ public enum IrisTerrainPass {
|
||||
}
|
||||
|
||||
public boolean isShadow() {
|
||||
return this == SHADOW || this == SHADOW_CUTOUT;
|
||||
return this == SHADOW || this == SHADOW_CUTOUT || this == SHADOW_TRANSLUCENT;
|
||||
}
|
||||
|
||||
public TerrainRenderPass toTerrainPass(RenderPassConfiguration<?> config) {
|
||||
return switch (this) {
|
||||
case SHADOW, GBUFFER_SOLID -> config.defaultSolidMaterial().pass;
|
||||
case SHADOW_CUTOUT, GBUFFER_CUTOUT -> config.defaultCutoutMippedMaterial().pass;
|
||||
case GBUFFER_TRANSLUCENT -> config.defaultTranslucentMaterial().pass;
|
||||
case SHADOW_TRANSLUCENT, GBUFFER_TRANSLUCENT -> config.defaultTranslucentMaterial().pass;
|
||||
};
|
||||
}
|
||||
|
||||
public static IrisTerrainPass fromTerrainPass(TerrainRenderPass pass, boolean isShadow) {
|
||||
if (isShadow) {
|
||||
if (pass.isReverseOrder()) {
|
||||
return SHADOW_TRANSLUCENT;
|
||||
}
|
||||
return pass.supportsFragmentDiscard() ? SHADOW_CUTOUT : SHADOW;
|
||||
} else if (pass.supportsFragmentDiscard()) {
|
||||
return GBUFFER_CUTOUT;
|
||||
|
||||
@@ -18,6 +18,7 @@ public enum RenderCondition {
|
||||
HAND_TRANSLUCENT,
|
||||
RAIN_SNOW,
|
||||
WORLD_BORDER,
|
||||
SHADOW_TRANSLUCENT,
|
||||
// NB: Must be last due to implementation details of DeferredWorldRenderingPipeline
|
||||
SHADOW
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
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,11 +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.Vector2ic;
|
||||
import org.joml.Vector3ic;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4i;
|
||||
import org.joml.Vector4fc;
|
||||
import org.joml.Vector4ic;
|
||||
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.IntSupplier;
|
||||
@@ -38,7 +37,7 @@ 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;
|
||||
@@ -50,7 +49,7 @@ public interface DynamicLocationalUniformHolder extends LocationalUniformHolder,
|
||||
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;
|
||||
@@ -61,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,11 +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.Vector2ic;
|
||||
import org.joml.Vector3ic;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4i;
|
||||
import org.joml.Vector4fc;
|
||||
import org.joml.Vector4ic;
|
||||
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.IntSupplier;
|
||||
@@ -16,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 uniform2i(String name, Supplier<Vector2ic> value, ValueUpdateNotifier notifier);
|
||||
DynamicUniformHolder uniform3i(String name, Supplier<Vector3ic> value, ValueUpdateNotifier notifier);
|
||||
DynamicUniformHolder uniform4f(String name, Supplier<Vector4f> 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);
|
||||
}
|
||||
@@ -4,13 +4,13 @@ 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.Vector3ic;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.BooleanSupplier;
|
||||
@@ -66,7 +66,7 @@ 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;
|
||||
@@ -94,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;
|
||||
@@ -108,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;
|
||||
|
||||
@@ -3,12 +3,12 @@ package net.coderbot.iris.gl.uniform;
|
||||
import net.minecraft.util.Vec3;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
import org.joml.Vector2ic;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3fc;
|
||||
import org.joml.Vector3i;
|
||||
import org.joml.Vector3ic;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.DoubleSupplier;
|
||||
@@ -28,7 +28,7 @@ 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<Vector3fc> value);
|
||||
|
||||
@@ -36,11 +36,11 @@ public interface UniformHolder {
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector3fc;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -31,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());
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -220,11 +220,13 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
final Optional<ProgramSource> terrainSource = first(programs.getGbuffersTerrain(), programs.getGbuffersTexturedLit(), programs.getGbuffersTextured(), programs.getGbuffersBasic());
|
||||
final Optional<ProgramSource> translucentSource = first(programs.getGbuffersWater(), terrainSource);
|
||||
final Optional<ProgramSource> shadowSource = programs.getShadow();
|
||||
final Optional<ProgramSource> shadowTranslucentSource = first(programs.getShadowWater(), shadowSource);
|
||||
|
||||
// Celeritas terrain transform futures
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasTerrainFuture = terrainSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasTranslucentFuture = translucentSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasShadowFuture = shadowSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasShadowTranslucentFuture = shadowTranslucentSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
|
||||
this.cloudSetting = programs.getPackDirectives().getCloudSetting();
|
||||
this.shouldRenderUnderwaterOverlay = programs.getPackDirectives().underwaterOverlay();
|
||||
@@ -388,6 +390,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
null, null, ProgramId.Weather,
|
||||
// world border uses textured_lit even though it has no lightmap :/
|
||||
null, ProgramId.TexturedLit, ProgramId.TexturedLit,
|
||||
ProgramId.ShadowWater, ProgramId.ShadowWater, ProgramId.ShadowWater,
|
||||
ProgramId.Shadow, ProgramId.Shadow, ProgramId.Shadow
|
||||
};
|
||||
|
||||
@@ -431,7 +434,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
return cachedPasses.computeIfAbsent(Pair.of(id, availability), p -> {
|
||||
final ProgramSource source = resolver.resolveNullable(p.getLeft());
|
||||
|
||||
if (condition == RenderCondition.SHADOW) {
|
||||
if (condition == RenderCondition.SHADOW || condition == RenderCondition.SHADOW_TRANSLUCENT) {
|
||||
if (!shadowDirectives.isShadowEnabled().orElse(shadowRenderTargets != null)) {
|
||||
// shadow is not used
|
||||
return null;
|
||||
@@ -448,7 +451,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
|
||||
try {
|
||||
return createPass(source, availability, condition == RenderCondition.SHADOW, finalId);
|
||||
return createPass(source, availability,
|
||||
condition == RenderCondition.SHADOW || condition == RenderCondition.SHADOW_TRANSLUCENT, finalId);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to create pass for " + source.getName() + " for rendering condition "
|
||||
+ condition + " specialized to input availability " + availability, e);
|
||||
@@ -475,7 +479,9 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
this.shadowRenderer = new ShadowRenderer(programs.getShadow().orElse(null),
|
||||
programs.getPackDirectives(), shadowRenderTargets, shadowCompositeRenderer);
|
||||
Program shadowProgram = table.match(RenderCondition.SHADOW, new InputAvailability(true, true)).getProgram();
|
||||
shadowRenderer.setUsesImages(shadowProgram != null && shadowProgram.getActiveImages() > 0);
|
||||
Program shadowWaterProgram = table.match(RenderCondition.SHADOW_TRANSLUCENT, new InputAvailability(true, true)).getProgram();
|
||||
shadowRenderer.setUsesImages((shadowProgram != null && shadowProgram.getActiveImages() > 0)
|
||||
|| (shadowWaterProgram != null && shadowWaterProgram.getActiveImages() > 0));
|
||||
} else {
|
||||
shadowRenderer = null;
|
||||
}
|
||||
@@ -592,7 +598,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
terrainSource,
|
||||
translucentSource,
|
||||
shadowSource,
|
||||
celeritasTerrainFuture, celeritasTranslucentFuture, celeritasShadowFuture,
|
||||
shadowTranslucentSource,
|
||||
celeritasTerrainFuture, celeritasTranslucentFuture, celeritasShadowFuture, celeritasShadowTranslucentFuture,
|
||||
renderTargets, flippedAfterPrepare, flippedAfterTranslucent,
|
||||
celeritasShadowFb);
|
||||
|
||||
@@ -699,7 +706,10 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
private RenderCondition getCondition(WorldRenderingPhase phase) {
|
||||
if (isRenderingShadow) {
|
||||
return RenderCondition.SHADOW;
|
||||
return switch (phase) {
|
||||
case TERRAIN_TRANSLUCENT, TRIPWIRE -> RenderCondition.SHADOW_TRANSLUCENT;
|
||||
default -> RenderCondition.SHADOW;
|
||||
};
|
||||
}
|
||||
|
||||
if (special != null) {
|
||||
|
||||
@@ -39,56 +39,54 @@ public class PatchedShaderPrinter {
|
||||
}
|
||||
|
||||
public static void debugPatchedShaders(String name, String vertex, String geometry, String tessControl, String tessEval, String fragment, String compute) {
|
||||
if (!Iris.getIrisConfig().areDebugOptionsEnabled()) {
|
||||
if (!prettyPrintShaders && !Iris.getIrisConfig().areDebugOptionsEnabled()) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,6 +428,7 @@ public class ShaderTransformer {
|
||||
// Handle mc_midTexCoord for Celeritas
|
||||
patchMultiTexCoord3(transformer, parameters);
|
||||
replaceMidTexCoord(transformer, IrisExtendedChunkVertexType.MID_TEX_SCALE);
|
||||
replaceMCEntity(transformer, parameters);
|
||||
applyIntelHd4000Workaround(transformer);
|
||||
break;
|
||||
case COMPOSITE:
|
||||
@@ -494,6 +495,55 @@ public class ShaderTransformer {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces shader-declared mc_Entity (vec2/ivec2/float/int/etc.) with upstream-compatible unpacking
|
||||
* from a single uint attribute. The uint is packed as ((blockId + 1) << 1) | (renderType & 1).
|
||||
*/
|
||||
public static void replaceMCEntity(Transformer transformer, Parameters parameters) {
|
||||
if (parameters.type != ShaderType.VERTEX) return;
|
||||
|
||||
final int type = transformer.findType("mc_Entity");
|
||||
if (type != 0) {
|
||||
transformer.removeVariable("mc_Entity");
|
||||
}
|
||||
transformer.replaceExpression("mc_Entity", "iris_Entity");
|
||||
switch (type) {
|
||||
case 0:
|
||||
case GLSLLexer.BOOL:
|
||||
return;
|
||||
case GLSLLexer.FLOAT:
|
||||
transformer.injectFunction("float iris_Entity = float(int(mc_Entity >> 1u) - 1);");
|
||||
break;
|
||||
case GLSLLexer.VEC2:
|
||||
transformer.injectFunction("vec2 iris_Entity = vec2(int(mc_Entity >> 1u) - 1, mc_Entity & 1u);");
|
||||
break;
|
||||
case GLSLLexer.VEC3:
|
||||
transformer.injectFunction("vec3 iris_Entity = vec3(int(mc_Entity >> 1u) - 1, mc_Entity & 1u, 0.0);");
|
||||
break;
|
||||
case GLSLLexer.VEC4:
|
||||
transformer.injectFunction("vec4 iris_Entity = vec4(int(mc_Entity >> 1u) - 1, mc_Entity & 1u, 0.0, 1.0);");
|
||||
break;
|
||||
case GLSLLexer.UINT:
|
||||
transformer.injectFunction("uint iris_Entity = uint(int(mc_Entity >> 1u) - 1);");
|
||||
break;
|
||||
case GLSLLexer.INT:
|
||||
transformer.injectFunction("int iris_Entity = int(mc_Entity >> 1u) - 1;");
|
||||
break;
|
||||
case GLSLLexer.IVEC2:
|
||||
transformer.injectFunction("ivec2 iris_Entity = ivec2(int(mc_Entity >> 1u) - 1, mc_Entity & 1u);");
|
||||
break;
|
||||
case GLSLLexer.IVEC3:
|
||||
transformer.injectFunction("ivec3 iris_Entity = ivec3(int(mc_Entity >> 1u) - 1, mc_Entity & 1u, 0);");
|
||||
break;
|
||||
case GLSLLexer.IVEC4:
|
||||
transformer.injectFunction("ivec4 iris_Entity = ivec4(int(mc_Entity >> 1u) - 1, mc_Entity & 1u, 0, 1);");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Got an invalid format mc_Entity (type token " + type + ").");
|
||||
}
|
||||
transformer.injectVariable("in uint mc_Entity;");
|
||||
}
|
||||
|
||||
public static void addIfNotExists(Transformer transformer, String name, String code) {
|
||||
if (!transformer.hasVariable(name)) {
|
||||
transformer.injectVariable(code);
|
||||
|
||||
@@ -16,6 +16,7 @@ public class ProgramSet {
|
||||
private final PackDirectives packDirectives;
|
||||
|
||||
private final ProgramSource shadow;
|
||||
private final ProgramSource shadowWater;
|
||||
private final ComputeSource[] shadowCompute;
|
||||
|
||||
private final ProgramSource[] shadowcomp;
|
||||
@@ -80,6 +81,8 @@ public class ProgramSet {
|
||||
// - https://github.com/IrisShaders/Iris/issues/987
|
||||
this.shadow = readProgramSource(directory, sourceProvider, "shadow", this, shaderProperties,
|
||||
BlendModeOverride.OFF);
|
||||
this.shadowWater = readProgramSource(directory, sourceProvider, "shadow_water", this, shaderProperties,
|
||||
BlendModeOverride.OFF);
|
||||
this.shadowCompute = readComputeArray(directory, sourceProvider, "shadow");
|
||||
|
||||
this.shadowcomp = readProgramArray(directory, sourceProvider, "shadowcomp", shaderProperties);
|
||||
@@ -218,6 +221,7 @@ public class ProgramSet {
|
||||
List<ComputeSource> computes = new ArrayList<>();
|
||||
|
||||
programs.add(shadow);
|
||||
programs.add(shadowWater);
|
||||
programs.addAll(Arrays.asList(shadowcomp));
|
||||
programs.addAll(Arrays.asList(begin));
|
||||
programs.addAll(Arrays.asList(prepare));
|
||||
@@ -302,6 +306,10 @@ public class ProgramSet {
|
||||
return shadow.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getShadowWater() {
|
||||
return shadowWater.requireValid();
|
||||
}
|
||||
|
||||
public ProgramSource[] getShadowComposite() {
|
||||
return shadowcomp;
|
||||
}
|
||||
@@ -413,6 +421,7 @@ public class ProgramSet {
|
||||
public Optional<ProgramSource> get(ProgramId programId) {
|
||||
return switch (programId) {
|
||||
case Shadow -> getShadow();
|
||||
case ShadowWater -> first(getShadowWater(), getShadow());
|
||||
case Basic -> getGbuffersBasic();
|
||||
case Line -> gbuffersLine.requireValid();
|
||||
case Textured -> getGbuffersTextured();
|
||||
|
||||
@@ -14,6 +14,7 @@ public enum ProgramId {
|
||||
Shadow(ProgramGroup.Shadow, ""),
|
||||
ShadowSolid(ProgramGroup.Shadow, "solid", Shadow),
|
||||
ShadowCutout(ProgramGroup.Shadow, "cutout", Shadow),
|
||||
ShadowWater(ProgramGroup.Shadow, "water", Shadow, BlendModeOverride.OFF),
|
||||
|
||||
Basic(ProgramGroup.Gbuffers, "basic"),
|
||||
Line(ProgramGroup.Gbuffers, "line", Basic),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.uniforms;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
|
||||
|
||||
import org.joml.Vector4f;
|
||||
@@ -8,7 +9,8 @@ import org.joml.Vector4f;
|
||||
public class CapturedRenderingState {
|
||||
public static final CapturedRenderingState INSTANCE = new CapturedRenderingState();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Getter
|
||||
private float tickDelta;
|
||||
@Getter
|
||||
private int currentRenderedBlockEntity;
|
||||
@@ -29,10 +31,6 @@ public class CapturedRenderingState {
|
||||
private CapturedRenderingState() {
|
||||
}
|
||||
|
||||
public void setTickDelta(float tickDelta) {
|
||||
this.tickDelta = tickDelta;
|
||||
}
|
||||
|
||||
public void setCurrentBlockEntity(int entity) {
|
||||
this.currentRenderedBlockEntity = entity;
|
||||
|
||||
@@ -47,6 +45,7 @@ public class CapturedRenderingState {
|
||||
if (this.entityIdListener != null) {
|
||||
this.entityIdListener.run();
|
||||
}
|
||||
setCurrentRenderedItem(0);
|
||||
}
|
||||
|
||||
public void setCurrentEntityColor(float r, float g, float b, float a) {
|
||||
|
||||
@@ -41,9 +41,12 @@ import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE;
|
||||
public final class CommonUniforms {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
private static final Vector2i ZERO_VECTOR_2i = new Vector2i();
|
||||
private static final Vector4i ZERO_VECTOR_4i = new Vector4i(0, 0, 0, 0);
|
||||
private static final Vector3d ZERO_VECTOR_3d = new Vector3d();
|
||||
|
||||
// Scratch vectors for push-notified suppliers -- GL thread only, never escapes
|
||||
private static final Vector2i scratch2i = new Vector2i();
|
||||
private static final Vector4i scratch4i = new Vector4i();
|
||||
|
||||
private CommonUniforms() {
|
||||
// no construction allowed
|
||||
}
|
||||
@@ -79,27 +82,27 @@ public final class CommonUniforms {
|
||||
final AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId);
|
||||
if (texture instanceof TextureMap) {
|
||||
final TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId);
|
||||
return new Vector2i(info.getWidth(), info.getHeight());
|
||||
return scratch2i.set(info.getWidth(), info.getHeight());
|
||||
}
|
||||
|
||||
return ZERO_VECTOR_2i;
|
||||
}, ValueUpdateNotifier.NONE);
|
||||
return scratch2i.set(0, 0);
|
||||
}, StateUpdateNotifiers.bindTextureNotifier);
|
||||
|
||||
uniforms.uniform2i("gtextureSize", () -> {
|
||||
final int glId = GLStateManager.getBoundTextureForServerState(0);
|
||||
|
||||
final TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId);
|
||||
return new Vector2i(info.getWidth(), info.getHeight());
|
||||
return scratch2i.set(info.getWidth(), info.getHeight());
|
||||
|
||||
}, ValueUpdateNotifier.NONE);
|
||||
}, StateUpdateNotifiers.bindTextureNotifier);
|
||||
|
||||
uniforms.uniform4i("blendFunc", () -> {
|
||||
if(GLStateManager.getBlendMode().isEnabled()) {
|
||||
final BlendState blend = GLStateManager.getBlendState();
|
||||
return new Vector4i(blend.getSrcRgb(), blend.getDstRgb(), blend.getSrcAlpha(), blend.getDstAlpha());
|
||||
return scratch4i.set(blend.getSrcRgb(), blend.getDstRgb(), blend.getSrcAlpha(), blend.getDstAlpha());
|
||||
}
|
||||
return ZERO_VECTOR_4i;
|
||||
}, ValueUpdateNotifier.NONE);
|
||||
return scratch4i.set(0, 0, 0, 0);
|
||||
}, StateUpdateNotifiers.blendFuncNotifier);
|
||||
|
||||
uniforms.uniform1i("renderStage", () -> GbufferPrograms.getCurrentPhase().ordinal(), StateUpdateNotifiers.phaseChangeNotifier);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.coderbot.iris.uniforms;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.coderbot.iris.gl.state.FogMode;
|
||||
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
|
||||
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
|
||||
import net.coderbot.iris.gl.uniform.DynamicUniformHolder;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
@@ -19,12 +20,12 @@ public class FogUniforms {
|
||||
uniforms.uniform1i("fogMode", () -> {
|
||||
if (!GLStateManager.getFogMode().isEnabled()) return 0;
|
||||
return GLStateManager.getFogState().getFogMode();
|
||||
}, ValueUpdateNotifier.NONE);
|
||||
}, StateUpdateNotifiers.fogModeNotifier);
|
||||
uniforms.uniform1i("fogShape", () -> 0, ValueUpdateNotifier.NONE);
|
||||
}
|
||||
|
||||
uniforms.uniform1f("fogDensity", () -> GLStateManager.getFogState().getDensity(), ValueUpdateNotifier.NONE);
|
||||
uniforms.uniform1f("fogStart", () -> GLStateManager.getFogState().getStart(), ValueUpdateNotifier.NONE);
|
||||
uniforms.uniform1f("fogEnd", () -> GLStateManager.getFogState().getEnd(), ValueUpdateNotifier.NONE);
|
||||
uniforms.uniform1f("fogDensity", () -> GLStateManager.getFogState().getDensity(), StateUpdateNotifiers.fogDensityNotifier);
|
||||
uniforms.uniform1f("fogStart", () -> GLStateManager.getFogState().getStart(), StateUpdateNotifiers.fogStartNotifier);
|
||||
uniforms.uniform1f("fogEnd", () -> GLStateManager.getFogState().getEnd(), StateUpdateNotifiers.fogEndNotifier);
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package net.coderbot.iris.uniforms;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntFunction;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
@@ -22,8 +20,6 @@ import net.minecraft.util.ResourceLocation;
|
||||
public class ItemMaterialHelper {
|
||||
private static final Reference2ObjectMap<Item, Int2IntMap> MATERIAL_CACHE = new Reference2ObjectOpenHashMap<>();
|
||||
private static final int CACHE_MISS_SENTINEL = Integer.MIN_VALUE;
|
||||
public static final IntSet WARNED_UNKNOWN_ARMOR_INDICES = new IntOpenHashSet();
|
||||
|
||||
/**
|
||||
* Get the material ID for an ItemStack.
|
||||
* For ItemBlock: checks block.properties first, then item.properties.
|
||||
@@ -114,6 +110,5 @@ public class ItemMaterialHelper {
|
||||
*/
|
||||
public static void clearCache() {
|
||||
MATERIAL_CACHE.clear();
|
||||
WARNED_UNKNOWN_ARMOR_INDICES.clear();
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -22,12 +22,13 @@ 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.Vector3ic;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -112,7 +113,7 @@ public class CustomUniformFixedInputUniformsHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2i> value) {
|
||||
public Builder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2ic> value) {
|
||||
return this.put(name, new Int2VectorCachedUniform(name, updateFrequency, value));
|
||||
}
|
||||
|
||||
@@ -132,10 +133,10 @@ public class CustomUniformFixedInputUniformsHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4f> value) {
|
||||
public Builder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4fc> value) {
|
||||
Vector3f held = new Vector3f();
|
||||
return this.put(name, new Float3VectorCachedUniform(name, updateFrequency, () -> {
|
||||
Vector4f vec = value.get();
|
||||
final Vector4fc vec = value.get();
|
||||
held.set(vec.x(), vec.y(), vec.z());
|
||||
return held;
|
||||
}));
|
||||
@@ -152,10 +153,10 @@ public class CustomUniformFixedInputUniformsHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4f> value) {
|
||||
public UniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector4fc> value) {
|
||||
Vector4f held = new Vector4f();
|
||||
return this.put(name, new Float4VectorCachedUniform(name, updateFrequency, () -> {
|
||||
Vector4f vec = value.get();
|
||||
final Vector4fc vec = value.get();
|
||||
held.set(vec.x(), vec.y(), vec.z(), vec.w());
|
||||
return held;
|
||||
}));
|
||||
|
||||
+11
-2
@@ -3,14 +3,23 @@ package net.coderbot.iris.uniforms.custom.cached;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
import net.coderbot.iris.parsing.VectorType;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class Float4VectorCachedUniform extends VectorCachedUniform<Vector4f> {
|
||||
|
||||
public Float4VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector4f> supplier) {
|
||||
super(name, updateFrequency, new Vector4f(), supplier);
|
||||
public Float4VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector4fc> supplier) {
|
||||
super(name, updateFrequency, new Vector4f(), adapt(supplier));
|
||||
}
|
||||
|
||||
private static Supplier<Vector4f> adapt(Supplier<Vector4fc> supplier) {
|
||||
final Vector4f scratch = new Vector4f();
|
||||
return () -> {
|
||||
final Vector4fc v = supplier.get();
|
||||
return scratch.set(v.x(), v.y(), v.z(), v.w());
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
-2
@@ -4,14 +4,23 @@ import kroppeb.stareval.function.FunctionReturn;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
import net.coderbot.iris.parsing.VectorType;
|
||||
import org.joml.Vector2i;
|
||||
import org.joml.Vector2ic;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class Int2VectorCachedUniform extends VectorCachedUniform<Vector2i> {
|
||||
|
||||
public Int2VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector2i> supplier) {
|
||||
super(name, updateFrequency, new Vector2i(), supplier);
|
||||
public Int2VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector2ic> supplier) {
|
||||
super(name, updateFrequency, new Vector2i(), adapt(supplier));
|
||||
}
|
||||
|
||||
private static Supplier<Vector2i> adapt(Supplier<Vector2ic> supplier) {
|
||||
final Vector2i scratch = new Vector2i();
|
||||
return () -> {
|
||||
final Vector2ic v = supplier.get();
|
||||
return scratch.set(v.x(), v.y());
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.coderbot.iris.uniforms.transforms;
|
||||
|
||||
import net.coderbot.iris.uniforms.FrameUpdateNotifier;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
import org.joml.Vector2ic;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -10,9 +10,9 @@ public class SmoothedVec2f implements Supplier<Vector2f> {
|
||||
private final SmoothedFloat x;
|
||||
private final SmoothedFloat y;
|
||||
|
||||
public SmoothedVec2f(float halfLifeUp, float halfLifeDown, Supplier<Vector2i> unsmoothed, FrameUpdateNotifier updateNotifier) {
|
||||
x = new SmoothedFloat(halfLifeUp, halfLifeDown, () -> unsmoothed.get().x, updateNotifier);
|
||||
y = new SmoothedFloat(halfLifeUp, halfLifeDown, () -> unsmoothed.get().y, updateNotifier);
|
||||
public SmoothedVec2f(float halfLifeUp, float halfLifeDown, Supplier<Vector2ic> unsmoothed, FrameUpdateNotifier updateNotifier) {
|
||||
x = new SmoothedFloat(halfLifeUp, halfLifeDown, () -> unsmoothed.get().x(), updateNotifier);
|
||||
y = new SmoothedFloat(halfLifeUp, halfLifeDown, () -> unsmoothed.get().y(), updateNotifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.coderbot.iris.vertices;
|
||||
|
||||
public final class ExtendedDataHelper {
|
||||
// TODO: Resolve render types for normal blocks?
|
||||
public static final short BLOCK_RENDER_TYPE = -1;
|
||||
// Packed mc_Entity only preserves one terrain/fluid bit, so normal blocks must encode as 0.
|
||||
public static final short BLOCK_RENDER_TYPE = 0;
|
||||
/** All fluids have a ShadersMod render type of 1, to match behavior of Minecraft 1.7 and earlier. */
|
||||
public static final short FLUID_RENDER_TYPE = 1;
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
|
||||
|
||||
import net.minecraft.client.model.ModelCreeper;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
|
||||
@Mixin(ModelCreeper.class)
|
||||
public class MixinModelCreeper_AuraBodyInflate {
|
||||
|
||||
/**
|
||||
* Reduce the body inflate by 2^20 ULPs so the aura body doesn't intersect the base model's head.
|
||||
* Only applies when inflate > 0 (the aura model), leaving the base model untouched.
|
||||
* The body addBox is the 3rd call (ordinal 2) in the constructor, and inflate is parameter index 6.
|
||||
*/
|
||||
@ModifyArg(
|
||||
method = "<init>(F)V", at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/model/ModelRenderer;addBox(FFFIIIF)V", ordinal = 2), index = 6
|
||||
)
|
||||
private float angelica$shrinkAuraBody(float inflate) {
|
||||
if (inflate > 0.0F) {
|
||||
return Float.intBitsToFloat(Float.floatToIntBits(inflate) - 1048576);
|
||||
}
|
||||
return inflate;
|
||||
}
|
||||
}
|
||||
+15
-5
@@ -5,6 +5,7 @@ import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.client.model.ModelWither;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@@ -26,8 +27,17 @@ public class MixinModelWither_ArmorCentering {
|
||||
// Heads: [0] center, [1] left, [2] right
|
||||
@Shadow private ModelRenderer[] field_82904_b;
|
||||
|
||||
@Unique
|
||||
private static final float ARMOR_INFLATE = 0.5F;
|
||||
|
||||
// Ribs armor size is reduced by 2^22 ULPs to sit just inside the base spine, preventing z-fighting.
|
||||
@Unique
|
||||
private static final float NO_RIBS_Z_INFLATE = Float.intBitsToFloat(Float.floatToIntBits(ARMOR_INFLATE) - 4194304);
|
||||
|
||||
// Side head armor is inflated by 2^22 ULPs to make the armor sit above the base shoulder, preventing z-fighting.
|
||||
@Unique
|
||||
private static final float NO_HEADS_Z_INFLATE = Float.intBitsToFloat(Float.floatToIntBits(ARMOR_INFLATE) + 4194304);
|
||||
|
||||
// If the armor inflate flag is set, rebuild all boxes with uniform inflate.
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void angelica$applyInflate(CallbackInfo ci) {
|
||||
@@ -44,9 +54,9 @@ public class MixinModelWither_ArmorCentering {
|
||||
field_82905_a[1] = (new ModelRenderer(self)).setTextureSize(self.textureWidth, self.textureHeight);
|
||||
field_82905_a[1].setRotationPoint(-2.0F, 6.9F, -0.5F);
|
||||
field_82905_a[1].setTextureOffset(0, 22).addBox(0.0F, 0.0F, 0.0F, 3, 10, 3, ARMOR_INFLATE);
|
||||
field_82905_a[1].setTextureOffset(24, 22).addBox(-4.0F, 1.5F, 0.5F, 11, 2, 2, ARMOR_INFLATE);
|
||||
field_82905_a[1].setTextureOffset(24, 22).addBox(-4.0F, 4.0F, 0.5F, 11, 2, 2, ARMOR_INFLATE);
|
||||
field_82905_a[1].setTextureOffset(24, 22).addBox(-4.0F, 6.5F, 0.5F, 11, 2, 2, ARMOR_INFLATE);
|
||||
field_82905_a[1].setTextureOffset(24, 22).addBox(-4.0F, 1.5F, 0.5F, 11, 2, 2, NO_RIBS_Z_INFLATE);
|
||||
field_82905_a[1].setTextureOffset(24, 22).addBox(-4.0F, 4.0F, 0.5F, 11, 2, 2, NO_RIBS_Z_INFLATE);
|
||||
field_82905_a[1].setTextureOffset(24, 22).addBox(-4.0F, 6.5F, 0.5F, 11, 2, 2, NO_RIBS_Z_INFLATE);
|
||||
|
||||
// [2] Tail
|
||||
field_82905_a[2] = new ModelRenderer(self, 12, 22);
|
||||
@@ -58,13 +68,13 @@ public class MixinModelWither_ArmorCentering {
|
||||
|
||||
// [1] Left head
|
||||
field_82904_b[1] = new ModelRenderer(self, 32, 0);
|
||||
field_82904_b[1].addBox(-4.0F, -4.0F, -4.0F, 6, 6, 6, ARMOR_INFLATE);
|
||||
field_82904_b[1].addBox(-4.0F, -4.0F, -4.0F, 6, 6, 6, NO_HEADS_Z_INFLATE);
|
||||
field_82904_b[1].rotationPointX = -8.0F;
|
||||
field_82904_b[1].rotationPointY = 4.0F;
|
||||
|
||||
// [2] Right head
|
||||
field_82904_b[2] = new ModelRenderer(self, 32, 0);
|
||||
field_82904_b[2].addBox(-4.0F, -4.0F, -4.0F, 6, 6, 6, ARMOR_INFLATE);
|
||||
field_82904_b[2].addBox(-4.0F, -4.0F, -4.0F, 6, 6, 6, NO_HEADS_Z_INFLATE);
|
||||
field_82904_b[2].rotationPointX = 10.0F;
|
||||
field_82904_b[2].rotationPointY = 4.0F;
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.DeferredEntityOverlay;
|
||||
import net.minecraft.client.renderer.entity.RenderCreeper;
|
||||
import net.minecraft.client.renderer.entity.RendererLivingEntity;
|
||||
import net.minecraft.entity.monster.EntityCreeper;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(RenderCreeper.class)
|
||||
public abstract class MixinRenderCreeper_AuraDepth {
|
||||
|
||||
@Shadow
|
||||
protected abstract int shouldRenderPass(EntityCreeper entity, int pass, float partialTick);
|
||||
|
||||
@Unique
|
||||
private DeferredEntityOverlay.ShouldRenderPassFn angelica$cachedPassFn;
|
||||
|
||||
/**
|
||||
* Mark that a charged creeper aura pass is about to execute. The method runs normally
|
||||
* so any mixins added by mods within shouldRenderPass still fire. The flag is consumed by the
|
||||
* WrapOperation on renderPassModel.render() in doRender, which defers the actual render.
|
||||
* See MixinRendererLivingEntity_DeferredEntityOverlay
|
||||
*/
|
||||
@Inject(method = "shouldRenderPass(Lnet/minecraft/entity/monster/EntityCreeper;IF)I",
|
||||
at = @At("HEAD"))
|
||||
private void angelica$markOverlayPass(EntityCreeper creeper, int pass, float partialTick, CallbackInfoReturnable<Integer> cir) {
|
||||
if (pass == 1 && creeper.getPowered() && !DeferredEntityOverlay.isReplaying()) {
|
||||
if (angelica$cachedPassFn == null) {
|
||||
angelica$cachedPassFn = (entity, pass2, tick) -> this.shouldRenderPass((EntityCreeper) entity, pass2, tick);
|
||||
}
|
||||
DeferredEntityOverlay.markOverlayPass(
|
||||
angelica$cachedPassFn,
|
||||
(RendererLivingEntity) (Object) this,
|
||||
creeper, partialTick
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.DeferredEntityOverlay;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(RenderGlobal.class)
|
||||
public class MixinRenderGlobal_DeferredEntityOverlay {
|
||||
|
||||
/**
|
||||
* Clear stale deferred entries before collecting new ones.
|
||||
*/
|
||||
@Inject(method = "renderEntities", at = @At("HEAD"))
|
||||
private void angelica$clearStaleDeferredOverlays(CallbackInfo ci) {
|
||||
DeferredEntityOverlay.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render deferred entity overlays after all entities have been drawn,
|
||||
* so additive-blended overlays composite correctly without depth issues.
|
||||
*/
|
||||
@Inject(method = "renderEntities", at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/renderer/RenderHelper;enableStandardItemLighting()V"))
|
||||
private void angelica$renderDeferredOverlays(CallbackInfo ci) {
|
||||
DeferredEntityOverlay.renderAll();
|
||||
}
|
||||
}
|
||||
+29
-2
@@ -1,15 +1,20 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.DeferredEntityOverlay;
|
||||
import com.gtnewhorizons.angelica.rendering.WitherArmorState;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelWither;
|
||||
import net.minecraft.client.renderer.entity.RenderWither;
|
||||
import net.minecraft.client.renderer.entity.RendererLivingEntity;
|
||||
import net.minecraft.entity.boss.EntityWither;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* Replaces the Wither's glScalef(1.1) armor approach with a per-box inflated model.
|
||||
@@ -17,11 +22,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
* Not exactly mod friendly but we can figure that out later.
|
||||
*/
|
||||
@Mixin(RenderWither.class)
|
||||
public class MixinRenderWither_ArmorCentering {
|
||||
public abstract class MixinRenderWither_ArmorCentering {
|
||||
|
||||
@Shadow
|
||||
protected abstract int shouldRenderPass(EntityWither entity, int pass, float partialTick);
|
||||
|
||||
@Unique
|
||||
private ModelWither angelica$armorModel;
|
||||
|
||||
@Unique
|
||||
private DeferredEntityOverlay.ShouldRenderPassFn angelica$cachedPassFn;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void angelica$createArmorModel(CallbackInfo ci) {
|
||||
WitherArmorState.pendingInflate = true;
|
||||
@@ -38,7 +49,7 @@ public class MixinRenderWither_ArmorCentering {
|
||||
((RenderWither) (Object) this).setRenderPassModel(angelica$armorModel);
|
||||
}
|
||||
|
||||
// No-op glTranslatef
|
||||
// No-op the model offset translate (ordinal 1)
|
||||
@Redirect(
|
||||
method = "shouldRenderPass(Lnet/minecraft/entity/boss/EntityWither;IF)I",
|
||||
at = @At(value = "INVOKE",
|
||||
@@ -55,4 +66,20 @@ public class MixinRenderWither_ArmorCentering {
|
||||
)
|
||||
private void angelica$skipScale(float x, float y, float z) {
|
||||
}
|
||||
|
||||
// Mark the Wither's armor pass for deferred rendering.
|
||||
@Inject(method = "shouldRenderPass(Lnet/minecraft/entity/boss/EntityWither;IF)I",
|
||||
at = @At("HEAD"))
|
||||
private void angelica$markArmorPass(EntityWither wither, int pass, float partialTick, CallbackInfoReturnable<Integer> cir) {
|
||||
if (pass == 1 && wither.isArmored() && !DeferredEntityOverlay.isReplaying()) {
|
||||
if (angelica$cachedPassFn == null) {
|
||||
angelica$cachedPassFn = (entity, pass2, tick) -> this.shouldRenderPass((EntityWither) entity, pass2, tick);
|
||||
}
|
||||
DeferredEntityOverlay.markOverlayPass(
|
||||
angelica$cachedPassFn,
|
||||
(RendererLivingEntity) (Object) this,
|
||||
wither, partialTick
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.DeferredEntityOverlay;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.renderer.entity.RendererLivingEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = RendererLivingEntity.class, priority = 1200)
|
||||
public class MixinRendererLivingEntity_DeferredEntityOverlay {
|
||||
|
||||
/**
|
||||
* Intercepts the first renderPassModel.render() call in the shouldRenderPass loop.
|
||||
* When an entity overlay pass is active, captures the animation params and modelview
|
||||
* matrix for deferred rendering, skipping the immediate render.
|
||||
*/
|
||||
@WrapOperation(
|
||||
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V", at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/model/ModelBase;render(Lnet/minecraft/entity/Entity;FFFFFF)V", ordinal = 0)
|
||||
)
|
||||
private void angelica$maybeDeferOverlay(ModelBase model, Entity entity,
|
||||
float limbSwing, float limbSwingAmount, float ageInTicks,
|
||||
float headYaw, float headPitch, float scale,
|
||||
Operation<Void> original) {
|
||||
if (DeferredEntityOverlay.isOverlayPassActive()) {
|
||||
DeferredEntityOverlay.deferRender(limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch, scale);
|
||||
} else {
|
||||
original.call(model, entity, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch, scale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a stale overlayPassActive flag after the shouldRenderPass loop.
|
||||
* Handles the case where markOverlayPass fired but shouldRenderPass returned <= 0,
|
||||
* so renderPassModel.render() was never called and deferRender never consumed the flag.
|
||||
*/
|
||||
@Inject(
|
||||
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
|
||||
at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V")
|
||||
)
|
||||
private void angelica$clearStaleOverlayFlag(CallbackInfo ci) {
|
||||
DeferredEntityOverlay.clearStaleOverlayFlag();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -123,7 +123,7 @@ public abstract class MixinRenderBlocks {
|
||||
@ModifyExpressionValue(method = "renderStandardBlockWithColorMultiplier",
|
||||
at = @At(value = "FIELD", target = "Lnet/minecraft/init/Blocks;grass:Lnet/minecraft/block/BlockGrass;", opcode = Opcodes.GETSTATIC))
|
||||
private BlockGrass angelica$widenGrassCheck(BlockGrass grassBlock, @Local(argsOnly = true, ordinal = 0) Block block) {
|
||||
return (block instanceof BlockGrass bg) ? bg : grassBlock;
|
||||
return (block instanceof BlockGrass bg && block == ClientProxy.bopGrass) ? bg : grassBlock;
|
||||
}
|
||||
|
||||
/* Disable diffuse when celeritas AO is in use */
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import net.minecraft.entity.passive.EntityHorse;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(EntityHorse.class)
|
||||
public interface AccessorEntityHorse {
|
||||
|
||||
@Invoker("getHorseArmorIndex")
|
||||
int invokeGetHorseArmorIndex(ItemStack stack);
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArgs;
|
||||
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
|
||||
|
||||
/**
|
||||
* Fix enchantment glint not rendering on item edges by using the actual icon dimensions
|
||||
* instead of hardcoded 256x256. This ensures the edge geometry calculation matches the
|
||||
* main item render, allowing GL_EQUAL depth test to pass on all edges.
|
||||
*/
|
||||
@Mixin(ItemRenderer.class)
|
||||
public class MixinHeldItemGlintEdges {
|
||||
|
||||
/**
|
||||
* First glint pass (ordinal 1)
|
||||
*/
|
||||
@ModifyArgs(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemRenderer;renderItemIn2D(Lnet/minecraft/client/renderer/Tessellator;FFFFIIF)V", ordinal = 1)
|
||||
)
|
||||
private void iris$fixFirstGlintDimensions(Args args, EntityLivingBase entity, ItemStack stack, int pass, ItemRenderType type) {
|
||||
IIcon icon = entity.getItemIcon(stack, pass);
|
||||
if (icon != null) {
|
||||
args.set(5, icon.getIconWidth());
|
||||
args.set(6, icon.getIconHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Second glint pass (ordinal 2)
|
||||
*/
|
||||
@ModifyArgs(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemRenderer;renderItemIn2D(Lnet/minecraft/client/renderer/Tessellator;FFFFIIF)V", ordinal = 2)
|
||||
)
|
||||
private void iris$fixSecondGlintDimensions(Args args, EntityLivingBase entity, ItemStack stack, int pass, ItemRenderType type) {
|
||||
IIcon icon = entity.getItemIcon(stack, pass);
|
||||
if (icon != null) {
|
||||
args.set(5, icon.getIconWidth());
|
||||
args.set(6, icon.getIconHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
+102
-50
@@ -1,84 +1,136 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.ModelHorseArmor;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.coderbot.iris.uniforms.ItemMaterialHelper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.client.renderer.entity.RenderHorse;
|
||||
import net.minecraft.entity.passive.EntityHorse;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mixin to set the currentRenderedItem ID when rendering horse armor.
|
||||
* This allows shaders to identify and apply different materials to horse armor.
|
||||
* Mixin to set the currentRenderedItem ID on the armor portion of horse rendering.
|
||||
*/
|
||||
@Mixin(RenderHorse.class)
|
||||
public abstract class MixinRenderHorse {
|
||||
@Unique
|
||||
private static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
|
||||
@Unique
|
||||
private static final float ARMOR_INFLATE = 0.125F;
|
||||
|
||||
@Unique
|
||||
private static ModelHorseArmor angelica$armorModel;
|
||||
|
||||
/**
|
||||
* Set the item ID when rendering the horse model if it has armor.
|
||||
* Wraps the mainModel.render() call to set the material ID only around the actual render.
|
||||
* Reverse mapping from armor index to Item, built lazily by scanning the item registry
|
||||
* for items recognized by EntityHorse.func_146085_a (isHorseArmor) and invoking
|
||||
* EntityHorse.getHorseArmorIndex to determine their index.
|
||||
* Automatically picks up modded armor that hooks into the vanilla's system. (I hope)
|
||||
*/
|
||||
@Unique
|
||||
private static Int2ObjectOpenHashMap<Item> angelica$armorIndexToItem;
|
||||
|
||||
@Unique
|
||||
private static final Map<String, ResourceLocation> angelica$armorTextureCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Two-pass rendering with a separate inflated armor model:
|
||||
* Pass 1: Render the base horse with the composite texture, no item ID.
|
||||
* Pass 2: Render the inflated armor model with the armor-only texture and item ID set.
|
||||
* The inflate makes armor geometry sit above the base.
|
||||
* Alpha test discards transparent (non-armor) pixels.
|
||||
*/
|
||||
@WrapOperation(
|
||||
method = "renderModel(Lnet/minecraft/entity/passive/EntityHorse;FFFFFF)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/ModelBase;render(Lnet/minecraft/entity/Entity;FFFFFF)V")
|
||||
)
|
||||
private void iris$setHorseArmorItemId(ModelBase model, net.minecraft.entity.Entity entity, float p1, float p2, float p3, float p4, float p5, float p6, Operation<Void> original, EntityHorse horse) {
|
||||
// Only set ID if horse has armor equipped
|
||||
boolean hasArmor = false;
|
||||
|
||||
// Check if horse type == 0 (regular horse)
|
||||
if (horse.func_110259_cr()) {
|
||||
// Get armor index from DataWatcher (synced from server)
|
||||
int armorIndex = horse.func_110241_cb();
|
||||
|
||||
if (armorIndex > 0) {
|
||||
// Map armor index to vanilla items
|
||||
Item armorItem = null;
|
||||
switch (armorIndex) {
|
||||
case 1:
|
||||
armorItem = Items.iron_horse_armor;
|
||||
break;
|
||||
case 2:
|
||||
armorItem = Items.golden_horse_armor;
|
||||
break;
|
||||
case 3:
|
||||
armorItem = Items.diamond_horse_armor;
|
||||
break;
|
||||
default:
|
||||
// Unknown armor index - likely from a mod
|
||||
// Warn once per unique index to avoid spam
|
||||
if (!ItemMaterialHelper.WARNED_UNKNOWN_ARMOR_INDICES.contains(armorIndex)) {
|
||||
ItemMaterialHelper.WARNED_UNKNOWN_ARMOR_INDICES.add(armorIndex);
|
||||
LOGGER.warn("Unknown horse armor index detected: {}. " +
|
||||
"This is likely from a mod. Vanilla horse armor uses indices 1-3 (iron/gold/diamond). " +
|
||||
"Modded horse armor material IDs are not currently supported.", armorIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (armorItem != null) {
|
||||
int id = ItemMaterialHelper.getMaterialId(armorItem, 0);
|
||||
CapturedRenderingState.INSTANCE.setCurrentRenderedItem(id);
|
||||
hasArmor = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call original render
|
||||
// Pass 1: Render the base horse normally
|
||||
original.call(model, entity, p1, p2, p3, p4, p5, p6);
|
||||
|
||||
// Reset only if we set it
|
||||
if (hasArmor) {
|
||||
ItemIdManager.resetItemId();
|
||||
if (!horse.func_110259_cr()) return;
|
||||
|
||||
int armorIndex = horse.func_110241_cb();
|
||||
if (armorIndex <= 0) return;
|
||||
|
||||
String armorTexturePath = horse.getVariantTexturePaths()[2];
|
||||
if (armorTexturePath == null) return;
|
||||
|
||||
// Pass 2: Render inflated armor model with item ID
|
||||
if (angelica$armorModel == null) {
|
||||
angelica$armorModel = new ModelHorseArmor(ARMOR_INFLATE);
|
||||
}
|
||||
|
||||
Item armorItem = angelica$getArmorItem(horse, armorIndex);
|
||||
if (armorItem != null) {
|
||||
int id = ItemMaterialHelper.getMaterialId(armorItem, 0);
|
||||
CapturedRenderingState.INSTANCE.setCurrentRenderedItem(id);
|
||||
}
|
||||
|
||||
// Copy animation state from the base model to the armor model
|
||||
angelica$copyRotations(model, angelica$armorModel);
|
||||
|
||||
ResourceLocation armorTexture = angelica$armorTextureCache.computeIfAbsent(armorTexturePath, ResourceLocation::new);
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(armorTexture);
|
||||
|
||||
angelica$armorModel.render(horse, p1, p2, p3, p4, p5, p6);
|
||||
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
// Copy rotation angles and positions from one model's renderers to another's
|
||||
@Unique
|
||||
private static void angelica$copyRotations(ModelBase from, ModelBase to) {
|
||||
for (int i = 0; i < from.boxList.size() && i < to.boxList.size(); i++) {
|
||||
ModelRenderer src = from.boxList.get(i);
|
||||
ModelRenderer dst = to.boxList.get(i);
|
||||
dst.rotateAngleX = src.rotateAngleX;
|
||||
dst.rotateAngleY = src.rotateAngleY;
|
||||
dst.rotateAngleZ = src.rotateAngleZ;
|
||||
dst.rotationPointX = src.rotationPointX;
|
||||
dst.rotationPointY = src.rotationPointY;
|
||||
dst.rotationPointZ = src.rotationPointZ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the item for a given armor index. On first call, builds a reverse mapping
|
||||
* by scanning the item registry for items that pass EntityHorse.func_146085_a (isHorseArmor)
|
||||
* and invoking the getHorseArmorIndex to determine their index.
|
||||
*/
|
||||
@Unique
|
||||
private static Item angelica$getArmorItem(EntityHorse horse, int armorIndex) {
|
||||
if (angelica$armorIndexToItem == null) {
|
||||
angelica$armorIndexToItem = new Int2ObjectOpenHashMap<>();
|
||||
AccessorEntityHorse accessor = (AccessorEntityHorse) horse;
|
||||
for (Object obj : Item.itemRegistry) {
|
||||
Item item = (Item) obj;
|
||||
if (!EntityHorse.func_146085_a(item)) continue;
|
||||
int idx = accessor.invokeGetHorseArmorIndex(new ItemStack(item));
|
||||
if (idx > 0) {
|
||||
angelica$armorIndexToItem.put(idx, item);
|
||||
}
|
||||
}
|
||||
LOGGER.debug("Built horse armor index map: {} entries", angelica$armorIndexToItem.size());
|
||||
}
|
||||
return angelica$armorIndexToItem.get(armorIndex);
|
||||
}
|
||||
}
|
||||
@@ -30,17 +30,6 @@ public class MixinRenderItem {
|
||||
ItemIdManager.setItemId(itemStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the item ID after rendering dropped items.
|
||||
*/
|
||||
@Inject(
|
||||
method = "doRender(Lnet/minecraft/entity/item/EntityItem;DDDFF)V",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void iris$resetItemIdAfterRender(EntityItem entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate GLINT shader before rendering enchantment glint on dropped items.
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.EntityIdHelper;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -26,7 +25,6 @@ public class MixinRenderManager {
|
||||
private void iris$wrapDoRender(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
ItemIdManager.resetItemId();
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
}
|
||||
|
||||
-2
@@ -4,7 +4,6 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.EntityIdHelper;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -24,7 +23,6 @@ public class MixinRenderManagerDAPI {
|
||||
private void iris$wrapDoRenderDragonAPI(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
ItemIdManager.resetItemId();
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
}
|
||||
|
||||
+3
-4
@@ -22,13 +22,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(RendererLivingEntity.class)
|
||||
public class MixinRendererLivingEntity {
|
||||
/**
|
||||
* Reset currentRenderedItemId at the start of rendering each living entity.
|
||||
* Reset ID before damage overlay renders, otherwise you get random shiny zombies
|
||||
*/
|
||||
@Inject(
|
||||
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
|
||||
at = @At("HEAD")
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V", shift = At.Shift.AFTER)
|
||||
)
|
||||
private void iris$resetItemIdAtStart(EntityLivingBase entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) {
|
||||
private void iris$resetItemIdAfterEquipped(EntityLivingBase entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ public class MixinRendererLivingEntity {
|
||||
remap = false
|
||||
)
|
||||
private void iris$glintStart(CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.GLINT);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user