Compare commits

...
19 Commits
Author SHA1 Message Date
DarkShadow44 057ea8035c Distant Horizons shader support (#1553) 2026-03-25 10:48:14 -07:00
Jason Mitchell 3ea47c8385 Various fixes (#1571) 2026-03-24 22:17:40 -07:00
Eclipse-Sol 306d732d81 Fixes 3rd person enchant glints z-fighting with the item model (#1569) 2026-03-24 17:24:23 -07:00
Jason Mitchell a483669579 Maybe fix botania mana pool rendering 2026-03-23 21:09:33 -07:00
Eclipse-SolandJason Mitchell 53996500d7 Fix modded enchant glints not being animated (#1566)
Co-authored-by: Jason Mitchell <[email protected]>
2026-03-23 22:41:29 -04:00
Jason Mitchell 04dd8ce6c7 narrow scope of mixin per Eclipse 2026-03-23 19:24:16 -07:00
Jason Mitchell 8c9edfa4c3 Fix alpha test 2026-03-23 19:24:16 -07:00
Jason Mitchell 3f44195756 Change compat config 2026-03-23 09:27:56 -07:00
Jason Mitchell c98f056d74 ASM Hook Compat
* Adds a config to allow disabling
* Narrows Advanced LightSabers
* Narrows Alfheim (unreleased versions have compat, might make this version restricted)
2026-03-23 09:00:24 -07:00
Jason Mitchell 7e25f5d03e tweak wording 2026-03-22 18:41:58 -07:00
Jason Mitchell b5553654d0 More pass throughs 2026-03-22 18:41:58 -07:00
Jason Mitchell a3fffb47be Ban GL usage.
* Everything must go through GLSM/Render Backend
2026-03-22 11:56:08 -07:00
Jason Mitchell 09cc557be0 Clear cache on reload shaders 2026-03-22 11:07:37 -07:00
SpacEagle17 aff5ff7e7b Add a second profiles button to Angelica 2026-03-22 10:09:23 -07:00
Jason Mitchell e7d08a53b6 Add debug context 2026-03-22 10:08:49 -07:00
Jason Mitchell 3b2a0af5c4 Add missing overrides 2026-03-22 10:08:49 -07:00
Jason Mitchell 8c44e79990 Add always translucent config for brandyn 2026-03-22 10:08:49 -07:00
Jason Mitchell d2e491ed47 Misc fixes
* Add missing glMapBuffer overload
* Keep track of bound pixel buffer and suspend when needed
2026-03-21 22:07:15 -07:00
Jason Mitchell bccc5b00ca Supernova Support 2026-03-21 22:06:38 -07:00
105 changed files with 4582 additions and 1025 deletions

No files matched your search

+6 -1
View File
@@ -90,7 +90,7 @@ dependencies {
compileOnly "org.apache.ant:ant:1.8.2"
// Celeritas (transitive=false: deps provided by GTNHLib/runtime)
embedOnly("org.embeddedt.celeritas:celeritas-common:2.5.3-GTNH") { transitive = false }
embedOnly("org.embeddedt.celeritas:celeritas-common:2.5.4-GTNH") { transitive = false }
embedOnly("org.embeddedt.celeritas:celeritas-lwjgl2-service:2.5.3-GTNH") { transitive = false }
// Because who doesn't want NEI
@@ -136,6 +136,9 @@ dependencies {
// Better Crashes
compileOnly("com.github.GTNewHorizons:BetterCrashes:1.4.1-GTNH:dev")
// Distant Horizons
compileOnly("maven.modrinth:DistantHorizonsApi:5.1.0")
afterEvaluate {
dependencies {
testImplementation(platform('org.junit:junit-bom:5.14.1'))
@@ -146,6 +149,8 @@ dependencies {
testImplementation('org.junit.platform:junit-platform-engine')
testImplementation('org.junit.platform:junit-platform-reporting')
testImplementation('org.junit.platform:junit-platform-launcher')
testImplementation('com.tngtech.archunit:archunit-junit5:1.4.1')
}
}
@@ -42,10 +42,11 @@ public class CompatUniformManager {
static final int LOC_IRIS_PROJECTION = 11;
static final int LOC_IRIS_NORMAL = 12;
static final int LOC_IRIS_LIGHTMAP_TEXTURE_MATRIX = 13;
static final int LOC_ALPHA_TEST_REF = 14;
static final int LOC_SCENE_COLOR = 15;
static final int LOC_CLIP_PLANES = 16;
static final int LOC_CLIP_PLANES_ENABLED = 17;
static final int LOC_IRIS_TEXTURE_MATRIX = 14;
static final int LOC_ALPHA_TEST_REF = 15;
static final int LOC_SCENE_COLOR = 16;
static final int LOC_CLIP_PLANES = 17;
static final int LOC_CLIP_PLANES_ENABLED = 18;
// Light source fields: 12 per light × 2 lights = 24 locations
static final int LIGHT_FIELDS = 12;
@@ -53,14 +54,14 @@ public class CompatUniformManager {
static final int LF_HALF_VECTOR = 4, LF_SPOT_DIRECTION = 5, LF_SPOT_EXPONENT = 6;
static final int LF_SPOT_CUTOFF = 7, LF_SPOT_COS_CUTOFF = 8;
static final int LF_CONSTANT_ATTEN = 9, LF_LINEAR_ATTEN = 10, LF_QUADRATIC_ATTEN = 11;
static final int LOC_LIGHT_BASE = 18;
static final int LOC_LIGHT_BASE = 19;
// Material fields: 5 locations
static final int MF_EMISSION = 0, MF_AMBIENT = 1, MF_DIFFUSE = 2, MF_SPECULAR = 3, MF_SHININESS = 4;
static final int MAT_FIELDS = 5;
static final int LOC_MAT_BASE = LOC_LIGHT_BASE + 2 * LIGHT_FIELDS; // 42
static final int LOC_MAT_BASE = LOC_LIGHT_BASE + 2 * LIGHT_FIELDS; // 43
static final int LOC_COUNT = LOC_MAT_BASE + MAT_FIELDS; // 47
static final int LOC_COUNT = LOC_MAT_BASE + MAT_FIELDS; // 48
private static final String[] LIGHT_FIELD_NAMES = {
"ambient", "diffuse", "specular", "position", "halfVector",
@@ -89,6 +90,7 @@ public class CompatUniformManager {
UNIFORM_NAMES[LOC_IRIS_PROJECTION] = "iris_ProjectionMatrix";
UNIFORM_NAMES[LOC_IRIS_NORMAL] = "iris_NormalMatrix";
UNIFORM_NAMES[LOC_IRIS_LIGHTMAP_TEXTURE_MATRIX] = "iris_LightmapTextureMatrix";
UNIFORM_NAMES[LOC_IRIS_TEXTURE_MATRIX] = "iris_TextureMatrix";
UNIFORM_NAMES[LOC_ALPHA_TEST_REF] = "angelica_currentAlphaTest";
UNIFORM_NAMES[LOC_SCENE_COLOR] = "angelica_SceneColor";
UNIFORM_NAMES[LOC_CLIP_PLANES] = "angelica_ClipPlane[0]";
@@ -264,6 +266,12 @@ public class CompatUniformManager {
GLStateManager.getTextures().getTextureUnitMatrix(1).get(mat4Buf);
RENDER_BACKEND.uniformMatrix4(locs[LOC_LIGHTMAP_TEXTURE_MATRIX], false, mat4Buf);
}
// iris_TextureMatrix — texture unit 0 matrix (animated by glints, etc.)
if (locs[LOC_IRIS_TEXTURE_MATRIX] != -1) {
GLStateManager.getTextures().getTextureUnitMatrix(0).get(mat4Buf);
RENDER_BACKEND.uniformMatrix4(locs[LOC_IRIS_TEXTURE_MATRIX], false, mat4Buf);
}
}
}
@@ -72,6 +72,7 @@ import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL21;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL32;
@@ -418,6 +419,8 @@ public class GLStateManager {
@Getter protected static int boundVBO;
@Getter protected static int boundEBO;
@Getter protected static int boundVAO;
private static int boundPixelUnpackBuffer;
private static int boundPixelPackBuffer;
private static final Int2IntOpenHashMap vaoEboMap = new Int2IntOpenHashMap();
static {
@@ -1005,6 +1008,8 @@ public class GLStateManager {
case GL15.GL_ARRAY_BUFFER_BINDING -> boundVBO;
case GL15.GL_ELEMENT_ARRAY_BUFFER_BINDING -> boundEBO;
case GL21.GL_PIXEL_UNPACK_BUFFER_BINDING -> boundPixelUnpackBuffer;
case GL21.GL_PIXEL_PACK_BUFFER_BINDING -> boundPixelPackBuffer;
case GL20.GL_CURRENT_PROGRAM -> activeProgram;
@@ -1789,6 +1794,7 @@ public class GLStateManager {
}
}
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
suspendPixelUnpackBuffer();
if (shouldUseDSA(target)) {
// Use DSA to upload directly to the texture
RenderSystem.textureImage2D(getBoundTextureForServerState(), target, level, internalformat, width, height, border, format, type, pixels);
@@ -1796,6 +1802,7 @@ public class GLStateManager {
// Non-main thread or proxy texture - use direct GL call
RENDER_BACKEND.texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
}
restorePixelUnpackBuffer();
}
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, FloatBuffer pixels) {
@@ -1808,7 +1815,9 @@ public class GLStateManager {
}
}
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
suspendPixelUnpackBuffer();
RENDER_BACKEND.texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, DoubleBuffer pixels) {
@@ -1821,7 +1830,9 @@ public class GLStateManager {
}
}
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
suspendPixelUnpackBuffer();
RENDER_BACKEND.texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) {
@@ -1834,13 +1845,13 @@ public class GLStateManager {
}
}
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : null);
suspendPixelUnpackBuffer();
if (shouldUseDSA(target)) {
// Use DSA to upload directly to the texture - keeps GL binding state unchanged
RenderSystem.textureImage2D(getBoundTextureForServerState(), target, level, internalformat, width, height, border, format, type, pixels);
} else {
// Non-main thread or proxy texture - use direct GL call
RENDER_BACKEND.texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
}
restorePixelUnpackBuffer();
}
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, long pixels_buffer_offset) {
@@ -3780,12 +3791,32 @@ public class GLStateManager {
};
}
public static void glGetTexImage(int target, int level, int format, int type, java.nio.ByteBuffer pixels) { RENDER_BACKEND.getTexImage(target, level, format, type, pixels); }
public static void glGetTexImage(int target, int level, int format, int type, java.nio.IntBuffer pixels) { RENDER_BACKEND.getTexImage(target, level, format, type, pixels); }
public static void glGetTexImage(int target, int level, int format, int type, java.nio.ByteBuffer pixels) {
suspendPixelPackBuffer();
RENDER_BACKEND.getTexImage(target, level, format, type, pixels);
restorePixelPackBuffer();
}
public static void glGetTexImage(int target, int level, int format, int type, java.nio.IntBuffer pixels) {
suspendPixelPackBuffer();
RENDER_BACKEND.getTexImage(target, level, format, type, pixels);
restorePixelPackBuffer();
}
public static void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer pixels) { RENDER_BACKEND.readPixels(x, y, width, height, format, type, pixels); }
public static void glReadPixels(int x, int y, int width, int height, int format, int type, FloatBuffer pixels) { RENDER_BACKEND.readPixels(x, y, width, height, format, type, pixels); }
public static void glReadPixels(int x, int y, int width, int height, int format, int type, IntBuffer pixels) { RENDER_BACKEND.readPixels(x, y, width, height, format, type, pixels); }
public static void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer pixels) {
suspendPixelPackBuffer();
RENDER_BACKEND.readPixels(x, y, width, height, format, type, pixels);
restorePixelPackBuffer();
}
public static void glReadPixels(int x, int y, int width, int height, int format, int type, FloatBuffer pixels) {
suspendPixelPackBuffer();
RENDER_BACKEND.readPixels(x, y, width, height, format, type, pixels);
restorePixelPackBuffer();
}
public static void glReadPixels(int x, int y, int width, int height, int format, int type, IntBuffer pixels) {
suspendPixelPackBuffer();
RENDER_BACKEND.readPixels(x, y, width, height, format, type, pixels);
restorePixelPackBuffer();
}
public static void glTexStorage2D(int target, int levels, int internalFormat, int width, int height) { RENDER_BACKEND.texStorage2D(target, levels, internalFormat, width, height); }
public static void glClearTexImage(int texture, int level, int format, int type, java.nio.ByteBuffer data) { RENDER_BACKEND.clearTexImage(texture, level, format, type); }
@@ -4201,7 +4232,9 @@ public class GLStateManager {
if (DisplayListManager.isRecording()) {
throw new UnsupportedOperationException("glTexImage1D in display lists not yet implemented");
}
suspendPixelUnpackBuffer();
RENDER_BACKEND.texImage1D(target, level, internalformat, width, border, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glTexImage3D(int target, int level, int internalformat, int width, int height, int depth, int border, int format, int type, ByteBuffer pixels) {
@@ -4209,7 +4242,9 @@ public class GLStateManager {
if (DisplayListManager.isRecording()) {
throw new UnsupportedOperationException("glTexImage3D in display lists not yet implemented");
}
suspendPixelUnpackBuffer();
RENDER_BACKEND.texImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glTexImage3D(int target, int level, int internalformat, int width, int height, int depth, int border, int format, int type, IntBuffer pixels) {
@@ -4217,14 +4252,18 @@ public class GLStateManager {
if (DisplayListManager.isRecording()) {
throw new UnsupportedOperationException("glTexImage3D in display lists not yet implemented");
}
suspendPixelUnpackBuffer();
RENDER_BACKEND.texImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glTexSubImage1D(int target, int level, int xoffset, int width, int format, int type, ByteBuffer pixels) {
if (DisplayListManager.isRecording()) {
throw new UnsupportedOperationException("glTexSubImage1D in display lists not yet implemented");
}
suspendPixelUnpackBuffer();
RENDER_BACKEND.texSubImage1D(target, level, xoffset, width, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glLineWidth(float width) {
@@ -4302,6 +4341,7 @@ public class GLStateManager {
return;
}
}
suspendPixelUnpackBuffer();
if (shouldUseDSA(target)) {
// Use DSA to upload directly to the texture - keeps GL binding state unchanged
RenderSystem.textureSubImage2D(getBoundTextureForServerState(), target, level, xoffset, yoffset, width, height, format, type, pixels);
@@ -4309,6 +4349,7 @@ public class GLStateManager {
// Non-main thread or proxy texture - use direct GL call
RENDER_BACKEND.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
restorePixelUnpackBuffer();
}
public static void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, IntBuffer pixels) {
@@ -4319,6 +4360,7 @@ public class GLStateManager {
return;
}
}
suspendPixelUnpackBuffer();
if (shouldUseDSA(target)) {
// Use DSA to upload directly to the texture
RenderSystem.textureSubImage2D(getBoundTextureForServerState(), target, level, xoffset, yoffset, width, height, format, type, pixels);
@@ -4326,6 +4368,7 @@ public class GLStateManager {
// Non-main thread or proxy texture - use direct GL call
RENDER_BACKEND.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
restorePixelUnpackBuffer();
}
public static void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, long pixels_buffer_offset) {
@@ -4339,7 +4382,9 @@ public class GLStateManager {
if (DisplayListManager.isRecording()) {
throw new UnsupportedOperationException("glTexSubImage3D in display lists not yet implemented - if you see this, please report!");
}
suspendPixelUnpackBuffer();
RENDER_BACKEND.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
restorePixelUnpackBuffer();
}
public static void glCopyTexImage1D(int target, int level, int internalFormat, int x, int y, int width, int border) {
@@ -4816,10 +4861,38 @@ public class GLStateManager {
} else if (target == GL15.GL_ELEMENT_ARRAY_BUFFER) {
boundEBO = buffer;
vaoEboMap.put(boundVAO, buffer);
} else if (target == GL21.GL_PIXEL_UNPACK_BUFFER) {
boundPixelUnpackBuffer = buffer;
} else if (target == GL21.GL_PIXEL_PACK_BUFFER) {
boundPixelPackBuffer = buffer;
}
RENDER_BACKEND.bindBuffer(target, buffer);
}
private static void suspendPixelUnpackBuffer() {
if (boundPixelUnpackBuffer != 0) {
RENDER_BACKEND.bindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, 0);
}
}
private static void restorePixelUnpackBuffer() {
if (boundPixelUnpackBuffer != 0) {
RENDER_BACKEND.bindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, boundPixelUnpackBuffer);
}
}
private static void suspendPixelPackBuffer() {
if (boundPixelPackBuffer != 0) {
RENDER_BACKEND.bindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);
}
}
private static void restorePixelPackBuffer() {
if (boundPixelPackBuffer != 0) {
RENDER_BACKEND.bindBuffer(GL21.GL_PIXEL_PACK_BUFFER, boundPixelPackBuffer);
}
}
public static int glGenBuffers() {
return RENDER_BACKEND.genBuffers();
}
@@ -4828,12 +4901,23 @@ public class GLStateManager {
public static void glBufferData(int target, int[] data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, float[] data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, java.nio.ByteBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, java.nio.FloatBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, java.nio.ShortBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, java.nio.IntBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, java.nio.FloatBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferData(int target, java.nio.DoubleBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
public static void glBufferSubData(int target, long offset, java.nio.ByteBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
public static void glBufferSubData(int target, long offset, java.nio.ShortBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
public static void glBufferSubData(int target, long offset, java.nio.IntBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
public static void glBufferSubData(int target, long offset, java.nio.FloatBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
public static void glBufferSubData(int target, long offset, java.nio.DoubleBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
public static ByteBuffer glMapBuffer(int target, int access) { return RENDER_BACKEND.mapBuffer(target, access); }
public static ByteBuffer glMapBuffer(int target, int access, long length, ByteBuffer old_buffer) { return RENDER_BACKEND.mapBuffer(target, access, length, old_buffer); }
public static boolean glUnmapBuffer(int target) { return RENDER_BACKEND.unmapBuffer(target); }
public static void glGetBufferSubData(int target, long offset, java.nio.ByteBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
public static void glGetBufferSubData(int target, long offset, java.nio.ShortBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
public static void glGetBufferSubData(int target, long offset, java.nio.IntBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
public static void glGetBufferSubData(int target, long offset, java.nio.FloatBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
public static void glGetBufferSubData(int target, long offset, java.nio.DoubleBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
public static int glGetBufferParameteri(int target, int pname) { return RENDER_BACKEND.getBufferParameteri(target, pname); }
public static void glBufferStorage(int target, java.nio.ByteBuffer data, int flags) { RENDER_BACKEND.bufferStorage(target, data, flags); }
public static void glBufferStorage(int target, long size, int flags) { RENDER_BACKEND.bufferStorage(target, size, flags); }
@@ -4949,6 +5033,14 @@ public class GLStateManager {
public static void glFramebufferTexture(int target, int attachment, int texture, int level) { RENDER_BACKEND.framebufferTexture(target, attachment, texture, level); }
public static void glGenerateMipmap(int target) {
RENDER_BACKEND.generateMipmap(target);
}
public static void glBlitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
RENDER_BACKEND.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
public static void setActiveTexture(int textureUnit) {
glActiveTexture(textureUnit);
}
@@ -902,6 +902,16 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
GL15.glBufferData(target, data, usage);
}
@Override
public void bufferData(int target, IntBuffer data, int usage) {
GL15.glBufferData(target, data, usage);
}
@Override
public void bufferData(int target, DoubleBuffer data, int usage) {
GL15.glBufferData(target, data, usage);
}
@Override
public void bufferData(int target, int[] data, int usage) {
final IntBuffer buffer = getIntArrayBuffer(data.length);
@@ -923,11 +933,36 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
GL15.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, ShortBuffer data) {
GL15.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, IntBuffer data) {
GL15.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, FloatBuffer data) {
GL15.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, DoubleBuffer data) {
GL15.glBufferSubData(target, offset, data);
}
@Override
public ByteBuffer mapBuffer(int target, int access) {
return GL15.glMapBuffer(target, access, null);
}
@Override
public ByteBuffer mapBuffer(int target, int access, long length, ByteBuffer old_buffer) {
return GL15.glMapBuffer(target, access, length, old_buffer);
}
@Override
public boolean unmapBuffer(int target) {
return GL15.glUnmapBuffer(target);
@@ -948,6 +983,26 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
GL15.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, ShortBuffer data) {
GL15.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, IntBuffer data) {
GL15.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, FloatBuffer data) {
GL15.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, DoubleBuffer data) {
GL15.glGetBufferSubData(target, offset, data);
}
@Override
public int getBufferParameteri(int target, int pname) {
return GL15.glGetBufferParameteri(target, pname);
@@ -208,14 +208,25 @@ public abstract class RenderBackend {
public abstract void bufferData(int target, ByteBuffer data, int usage);
public abstract void bufferData(int target, FloatBuffer data, int usage);
public abstract void bufferData(int target, ShortBuffer data, int usage);
public abstract void bufferData(int target, IntBuffer data, int usage);
public abstract void bufferData(int target, DoubleBuffer data, int usage);
public abstract void bufferData(int target, int[] data, int usage);
public abstract void bufferData(int target, float[] data, int usage);
public abstract void bufferSubData(int target, long offset, ByteBuffer data);
public abstract void bufferSubData(int target, long offset, ShortBuffer data);
public abstract void bufferSubData(int target, long offset, IntBuffer data);
public abstract void bufferSubData(int target, long offset, FloatBuffer data);
public abstract void bufferSubData(int target, long offset, DoubleBuffer data);
public abstract ByteBuffer mapBuffer(int target, int access);
public abstract ByteBuffer mapBuffer(int target, int access, long length, ByteBuffer old_buffer);
public abstract boolean unmapBuffer(int target);
public abstract void bufferStorage(int target, ByteBuffer data, int flags);
public abstract void bufferStorage(int target, long size, int flags);
public abstract void getBufferSubData(int target, long offset, ByteBuffer data);
public abstract void getBufferSubData(int target, long offset, ShortBuffer data);
public abstract void getBufferSubData(int target, long offset, IntBuffer data);
public abstract void getBufferSubData(int target, long offset, FloatBuffer data);
public abstract void getBufferSubData(int target, long offset, DoubleBuffer data);
public abstract int getBufferParameteri(int target, int pname);
public abstract boolean isBuffer(int buffer);
public abstract ByteBuffer mapBufferRange(int target, long offset, long length, int access);
@@ -893,6 +893,16 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
GL15C.glBufferData(target, data, usage);
}
@Override
public void bufferData(int target, IntBuffer data, int usage) {
GL15C.glBufferData(target, data, usage);
}
@Override
public void bufferData(int target, DoubleBuffer data, int usage) {
GL15C.glBufferData(target, data, usage);
}
@Override
public void bufferData(int target, int[] data, int usage) {
GL15C.glBufferData(target, data, usage);
@@ -908,11 +918,36 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
GL15C.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, ShortBuffer data) {
GL15C.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, IntBuffer data) {
GL15C.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, FloatBuffer data) {
GL15C.glBufferSubData(target, offset, data);
}
@Override
public void bufferSubData(int target, long offset, DoubleBuffer data) {
GL15C.glBufferSubData(target, offset, data);
}
@Override
public ByteBuffer mapBuffer(int target, int access) {
return GL15C.glMapBuffer(target, access);
}
@Override
public ByteBuffer mapBuffer(int target, int access, long length, ByteBuffer old_buffer) {
return GL15C.glMapBuffer(target, access, length, old_buffer);
}
@Override
public boolean unmapBuffer(int target) {
return GL15C.glUnmapBuffer(target);
@@ -933,6 +968,26 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
GL15C.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, ShortBuffer data) {
GL15C.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, IntBuffer data) {
GL15C.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, FloatBuffer data) {
GL15C.glGetBufferSubData(target, offset, data);
}
@Override
public void getBufferSubData(int target, long offset, DoubleBuffer data) {
GL15C.glGetBufferSubData(target, offset, data);
}
@Override
public int getBufferParameteri(int target, int pname) {
return GL15C.glGetBufferParameteri(target, pname);
@@ -0,0 +1,115 @@
package com.gtnewhorizons.angelica.api;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.chunk.Chunk;
/**
* Provides per-block RGB light color data for the rendering pipeline. Mods that replace the lighting engine (e.g. Supernova) implement this
* and register via {@link #register(BlockLightProvider)}.
*
*/
public interface BlockLightProvider {
/**
* Get RGB block light at the given world coordinates.
*
* @param blockAccess the block access context (WorldSlice on builder threads, World on main thread)
* @return packed RGB (see class Javadoc), or {@code -1} if no data is available
*/
int getBlockLightRGB(IBlockAccess blockAccess, int x, int y, int z);
/**
* Get RGB sky light at the given world coordinates.
*
* @param blockAccess the block access context (WorldSlice on builder threads, World on main thread)
* @return packed RGB (see class Javadoc), or {@code -1} if no data
*/
default int getSkyLightRGB(IBlockAccess blockAccess, int x, int y, int z) { return -1; }
/**
* Capture per-section light data on the main thread for use by builder threads.
* Called during {@code ClonedChunkSection.init()}.
*
* @return a {@link SectionLightData} snapshot, or {@code null} if not supported
*/
default SectionLightData prepareSectionData(Chunk chunk, int sectionY) {
return null;
}
/** Pack three 0-15 channels into a single int. */
static int packRGB(int r, int g, int b) {
return (r << 8) | (g << 4) | b;
}
/** Extract the red channel (0-15) from a packed RGB word. */
static int unpackR(int word) {
return (word >> 8) & 0xF;
}
/** Extract the green channel (0-15) from a packed RGB word. */
static int unpackG(int word) {
return (word >> 4) & 0xF;
}
/** Extract the blue channel (0-15) from a packed RGB word. */
static int unpackB(int word) {
return word & 0xF;
}
static BlockLightProvider getInstance() {
return Holder.INSTANCE;
}
static boolean isRegistered() {
return Holder.INSTANCE != Holder.DEFAULT;
}
/**
* Register the global block light provider. Must be called exactly once.
*
* @throws IllegalStateException if a provider has already been registered
*/
static void register(BlockLightProvider provider) {
if (Holder.INSTANCE != Holder.DEFAULT) {
throw new IllegalStateException("BlockLightProvider already registered: " + Holder.INSTANCE.getClass().getName() + ". Cannot register " + provider.getClass().getName());
}
Holder.INSTANCE = provider;
}
/**
* Call from your {@code IFMLLoadingPlugin} static initializer to enable colored light support.
* Must be called before mixin application (i.e. during coremod loading). Calling after mixins are frozen will throw.
*/
static void enableColoredLight() {
if (EarlyFlags.MIXINS_FROZEN) {
throw new IllegalStateException("Too late to enable colored light -- mixin configs have already been evaluated. Call BlockLightProvider.enableColoredLight() from your IFMLLoadingPlugin.");
}
EarlyFlags.COLORED_LIGHT = true;
}
/**
* Freeze the mixin config gate. After this call, {@link #enableColoredLight()} will throw.
* Called by the mixin config evaluation path before reading {@link #coloredLightEnabled()}.
*/
static void freezeMixinConfig() {
EarlyFlags.MIXINS_FROZEN = true;
}
/**
* Returns whether colored light support was enabled via {@link #enableColoredLight()}.
* Call {@link #freezeMixinConfig()} separately to close the enablement window.
*/
static boolean coloredLightEnabled() {
return EarlyFlags.COLORED_LIGHT;
}
final class EarlyFlags {
static boolean COLORED_LIGHT = false;
static boolean MIXINS_FROZEN = false;
}
final class Holder {
static final BlockLightProvider DEFAULT = (_, _, _, _) -> -1;
static BlockLightProvider INSTANCE = DEFAULT;
}
}
@@ -0,0 +1,34 @@
package com.gtnewhorizons.angelica.api;
/**
* Mixin interface for {@code AoFaceData} providing per-corner RGB light values.
* Each array has 4 elements corresponding to the quad's corner vertices.
*/
public interface ExtAoFaceData {
/** Per-corner red light values (block light, 0-15 range). */
float[] angelica$getRl();
/** Per-corner green light values (block light, 0-15 range). */
float[] angelica$getGl();
/** Per-corner blue light values (block light, 0-15 range). */
float[] angelica$getBl();
float angelica$getBlendedR(float[] w);
float angelica$getBlendedG(float[] w);
float angelica$getBlendedB(float[] w);
/** Per-corner red light values (sky light, 0-15 range). */
float[] angelica$getSkyRl();
/** Per-corner green light values (sky light, 0-15 range). */
float[] angelica$getSkyGl();
/** Per-corner blue light values (sky light, 0-15 range). */
float[] angelica$getSkyBl();
float angelica$getBlendedSkyR(float[] w);
float angelica$getBlendedSkyG(float[] w);
float angelica$getBlendedSkyB(float[] w);
}
@@ -0,0 +1,55 @@
package com.gtnewhorizons.angelica.api;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
/**
* Mixin interface for {@code LightDataAccess} providing per-block RGB light cache.
*
* <h3>Channel format</h3>
* Individual RGB words use the {@link BlockLightProvider} packing: {@code (r << 8) | (g << 4) | b}, each channel 0-15.
*
*/
public interface ExtLightDataAccess {
/** RGB block light at exact world coordinates. */
int angelica$getRGB(int x, int y, int z);
/** RGB block light offset one block in {@code dir} (face neighbor lookup). */
int angelica$getRGB(int x, int y, int z, ModelQuadFacing dir);
/** RGB block light offset by two directions (edge/corner neighbor for AO). */
int angelica$getRGB(int x, int y, int z, ModelQuadFacing d1, ModelQuadFacing d2);
boolean angelica$isRGBEnabled();
/** RGB sky light at exact world coordinates. */
int angelica$getSkyRGB(int x, int y, int z);
/** RGB sky light offset one block in {@code dir} (face neighbor lookup). */
int angelica$getSkyRGB(int x, int y, int z, ModelQuadFacing dir);
/** RGB sky light offset by two directions (edge/corner neighbor for AO). */
int angelica$getSkyRGB(int x, int y, int z, ModelQuadFacing d1, ModelQuadFacing d2);
boolean angelica$isSkyRGBEnabled();
/**
* Compute cache array index for the given world coordinates. Use with
* {@link #angelica$getRGBByIndex}, {@link #angelica$getSkyRGBByIndex}, or
* {@link #angelica$getFusedByIndex}
*/
int angelica$getIndex(int x, int y, int z);
/** Like {@link #angelica$getRGB(int, int, int)} but with a pre-computed cache index. */
int angelica$getRGBByIndex(int idx, int x, int y, int z);
/** Like {@link #angelica$getSkyRGB(int, int, int)} but with a pre-computed cache index. */
int angelica$getSkyRGBByIndex(int idx, int x, int y, int z);
/**
* Single cache lookup returning both block and sky RGB in the <b>cache format</b>.
* Upper 32 bits = block word (packed RGB | SENTINEL), lower 32 bits = sky word (packed RGB | SENTINEL).
*/
long angelica$getFusedByIndex(int idx, int x, int y, int z);
}
@@ -0,0 +1,11 @@
package com.gtnewhorizons.angelica.api;
import net.minecraft.world.IBlockAccess;
/**
* Interface for {@code LightDataCache} exposing its block access reference.
*/
public interface ExtLightDataCache {
IBlockAccess angelica$getBlockAccess();
}
@@ -0,0 +1,21 @@
package com.gtnewhorizons.angelica.api;
/**
* Interface for {@code QuadLightData} providing per-vertex RGB light values.
*/
public interface ExtQuadLightData {
float[] angelica$getR();
float[] angelica$getG();
float[] angelica$getB();
boolean angelica$isRGBValid();
void angelica$setRGBValid(boolean valid);
float[] angelica$getSkyR();
float[] angelica$getSkyG();
float[] angelica$getSkyB();
boolean angelica$isSkyRGBValid();
void angelica$setSkyRGBValid(boolean valid);
}
@@ -0,0 +1,41 @@
package com.gtnewhorizons.angelica.api;
/**
* Provides RGB light data for a single chunk section. Implemented by external providers (e.g. Supernova)
* and returned from {@link BlockLightProvider#prepareSectionData}.
*
* <h3>Transport format</h3>
* {@link #getRGBAndSkyRGB} returns a compact <b>transport format</b>: {@code ((block & 0xFFFF) << 16) | (sky & 0xFFFF)}.
*/
public interface SectionLightData {
/**
* Get RGB block light at section-local coordinates.
*
* @param localX 0-15
* @param localY 0-15
* @param localZ 0-15
* @return packed {@code (r << 8) | (g << 4) | b}, each channel 0-15, or {@code -1} if unavailable
*/
int getRGB(int localX, int localY, int localZ);
/**
* Get RGB sky light at section-local coordinates.
*
* @param localX 0-15
* @param localY 0-15
* @param localZ 0-15
* @return packed {@code (r << 8) | (g << 4) | b}, each channel 0-15, or {@code -1} if unavailable
*/
default int getSkyRGB(int localX, int localY, int localZ) { return -1; }
/**
* Get both block and sky RGB in a single call (transport format). Implementations can override
* to share index computation and apply section-level fast paths.
*
* @return {@code ((block & 0xFFFF) << 16) | (sky & 0xFFFF)}
*/
default long getRGBAndSkyRGB(int localX, int localY, int localZ) {
return ((long)(getRGB(localX, localY, localZ) & 0xFFFF) << 16) | (getSkyRGB(localX, localY, localZ) & 0xFFFF);
}
}
@@ -0,0 +1,21 @@
package com.gtnewhorizons.angelica.api;
/**
* Computes an RGB tint from block light and sky light channel values. The lightmap handles brightness; the tint only controls color.
*/
@FunctionalInterface
public interface TintComputer {
/**
* Blend block light RGB and sky light RGB into a tint color.
*
* @param br block light red (0-15)
* @param bg block light green (0-15)
* @param bb block light blue (0-15)
* @param sr sky light red (0-15, already adjusted for sky subtraction)
* @param sg sky light green (0-15)
* @param sb sky light blue (0-15)
* @param out float[3] output: R, G, B tint multipliers (typically 0-1)
*/
void computeTint(float br, float bg, float bb, float sr, float sg, float sb, float[] out);
}
@@ -0,0 +1,82 @@
package com.gtnewhorizons.angelica.api;
import java.util.ArrayList;
import java.util.List;
/**
* Registry for tint blend modes used by the colored light pipeline. Provides a default no-tint mode.
* External mods (e.g. Supernova) can register additional modes via {@link #registerMode(String, TintComputer)}.
*
*/
public final class TintRegistry {
private static final TintComputer NO_TINT = (br, bg, bb, sr, sg, sb, out) -> {
out[0] = 1f;
out[1] = 1f;
out[2] = 1f;
};
private static final List<TintComputer> computers = new ArrayList<>();
private static final List<String> names = new ArrayList<>();
private static TintComputer current;
private static volatile int currentOrdinal;
static {
registerMode("NONE", NO_TINT);
current = NO_TINT;
currentOrdinal = 0;
}
private TintRegistry() {}
/** Register a named tint blend mode. Returns the ordinal assigned. */
public static int registerMode(String name, TintComputer computer) {
final int ordinal = computers.size();
computers.add(computer);
names.add(name);
return ordinal;
}
/** Returns the currently active tint computer. */
public static TintComputer getCurrent() {
return current;
}
/** Returns the ordinal of the current mode, or -1 if a custom (non-registered) computer is active. */
public static int getCurrentOrdinal() {
return currentOrdinal;
}
/** Switch to a registered mode by ordinal. */
public static void setCurrentByOrdinal(int ordinal) {
if (ordinal < 0 || ordinal >= computers.size()) {
throw new IllegalArgumentException("Invalid tint mode ordinal: " + ordinal + " (registered modes: " + computers.size() + ")");
}
current = computers.get(ordinal);
currentOrdinal = ordinal;
}
/** Set a custom tint computer directly. */
public static void setCurrent(TintComputer computer) {
current = computer;
// Resolve ordinal; custom computers not in the registry get -1
for (int i = 0; i < computers.size(); i++) {
if (computers.get(i) == computer) {
currentOrdinal = i;
return;
}
}
currentOrdinal = -1;
}
/** Returns the number of registered blend modes. */
public static int getModeCount() {
return computers.size();
}
/** Returns the display name of a registered mode by ordinal. */
public static String getModeName(int ordinal) {
if (ordinal < 0 || ordinal >= names.size()) return "UNKNOWN";
return names.get(ordinal);
}
}
@@ -1,707 +0,0 @@
package com.gtnewhorizons.angelica.client.debug;
import com.gtnewhorizons.angelica.glsm.GLDebug;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
// Adapted from https://github.com/makamys/CoreTweaks/blob/master/src/main/java/makamys/coretweaks/util/OpenGLDebugging.java;
// originally from https://github.com/TheGreyGhost/MinecraftByExample/blob/1-8final/src/main/java/minecraftbyexample/usefultools/OpenGLdebugging.java
public class OpenGLDebugging {
public static final Logger LOGGER = LogManager.getLogger("gldumper");
private static final Consumer<String> LINE_LOGGER = LOGGER::debug;
private static final Set<String> seenErrors = new HashSet<>();
public static final String GL_IS_ENABLED = "glIsEnabled()";
public static final String GL_GET_BOOLEANV = "glGetBooleanv()";
public static final String GL_GET_INTEGERV = "glGetIntegerv()";
public static final String GL_GET_FLOATV = "glGetFloatv()";
public static class GLproperty {
public GLproperty(int glConstant, String name, String description, String category, String fetchCommand) {
this.gLConstant = glConstant;
this.name = name;
this.description = description;
this.category = category;
this.fetchCommand = fetchCommand;
}
public int gLConstant;
public String name;
public String description;
public String category;
public String fetchCommand;
static final ByteBuffer byteBuffer = BufferUtils.createByteBuffer(16);
static final IntBuffer intBuffer = BufferUtils.createIntBuffer(16);
static final FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(16);
public String getAsString(boolean glsm) {
switch(fetchCommand) {
case GL_IS_ENABLED: {
return "" + (glsm ? GLStateManager.glIsEnabled(gLConstant) : GL11.glIsEnabled(gLConstant));
}
case GL_GET_BOOLEANV: {
if(GLStateManager.HAS_MULTIPLE_SET.contains(gLConstant)) {
byteBuffer.clear();
if(glsm) {
GLStateManager.glGetBoolean(gLConstant, byteBuffer);
} else {
GL11.glGetBoolean(gLConstant, byteBuffer);
}
final StringBuilder out = new StringBuilder();
for (int i = 0; i < byteBuffer.capacity(); ++i) {
out.append(i == 0 ? "" : ", ").append(byteBuffer.get(i));
}
return out.toString();
} else {
return "" + (glsm ? GLStateManager.glGetBoolean(gLConstant) : GL11.glGetBoolean(gLConstant));
}
}
case GL_GET_INTEGERV: {
if(GLStateManager.HAS_MULTIPLE_SET.contains(gLConstant)) {
intBuffer.clear();
if(glsm) {
GLStateManager.glGetInteger(gLConstant, intBuffer);
} else {
GL11.glGetInteger(gLConstant, intBuffer);
}
final StringBuilder out = new StringBuilder();
for (int i = 0; i < intBuffer.remaining(); ++i) {
out.append(i == 0 ? "" : ", ").append(intBuffer.get(i));
}
return out.toString();
} else {
return "" + (glsm ? GLStateManager.glGetInteger(gLConstant) : GL11.glGetInteger(gLConstant));
}
}
case GL_GET_FLOATV: {
if(GLStateManager.HAS_MULTIPLE_SET.contains(gLConstant)) {
floatBuffer.clear();
if(glsm) {
GLStateManager.glGetFloat(gLConstant, floatBuffer);
} else {
GL11.glGetFloat(gLConstant, floatBuffer);
}
final StringBuilder out = new StringBuilder();
for (int i = 0; i < floatBuffer.remaining(); ++i) {
out.append(i == 0 ? "" : ", ").append(String.format("%f", floatBuffer.get(i)));
}
return out.toString();
} else {
return "" + (glsm ? GLStateManager.glGetFloat(gLConstant) : GL11.glGetFloat(gLConstant));
}
}
default: return "";
}
}
static final Matrix4f cachedMatrix = new Matrix4f();
static final Matrix4f uncachedMatrix = new Matrix4f();
public Matrix4f getAsMatrix4f(boolean glsm) {
if(!fetchCommand.equals(GL_GET_FLOATV)) {
throw new IllegalArgumentException("This property does not return a matrix");
}
floatBuffer.clear();
if(glsm) {
GLStateManager.glGetFloat(gLConstant, floatBuffer);
return cachedMatrix.set(0, floatBuffer);
} else {
GL11.glGetFloat(gLConstant, floatBuffer);
return uncachedMatrix.set(0, floatBuffer);
}
}
}
public static OpenGLDebugging instance = new OpenGLDebugging();
public GLproperty[] propertyList = {
new GLproperty(GL11.GL_ACCUM_ALPHA_BITS, "GL_ACCUM_ALPHA_BITS", "Number of bits per alpha component in the accumulation buffer", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ACCUM_BLUE_BITS, "GL_ACCUM_BLUE_BITS", "Number of bits per blue component in the accumulation buffer", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ACCUM_CLEAR_VALUE, "GL_ACCUM_CLEAR_VALUE", "Accumulation-buffer clear value", "accum-buffer", GL_GET_FLOATV),
new GLproperty(GL11.GL_ACCUM_GREEN_BITS, "GL_ACCUM_GREEN_BITS", "Number of bits per green component in the accumulation buffer", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ACCUM_RED_BITS, "GL_ACCUM_RED_BITS", "Number of bits per red component in the accumulation buffer", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ALPHA_BITS, "GL_ALPHA_BITS", "Number of bits per alpha component in color buffers", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ALPHA_TEST, "GL_ALPHA_TEST", "Alpha test enabled", "color-buffer/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_ALPHA_TEST_FUNC, "GL_ALPHA_TEST_FUNC", "Alpha test function", "color-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ALPHA_TEST_REF, "GL_ALPHA_TEST_REF", "Alpha test reference value", "color-buffer", GL_GET_FLOATV),
new GLproperty(GL11.GL_AMBIENT, "GL_AMBIENT", "Ambient intensity of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_AMBIENT, "GL_AMBIENT", "Ambient material color", "lighting", "glGetMaterialfv()"),
new GLproperty(GL11.GL_ATTRIB_STACK_DEPTH, "GL_ATTRIB_STACK_DEPTH", "Attribute stack pointer", "current", GL_GET_INTEGERV),
new GLproperty(GL11.GL_AUTO_NORMAL, "GL_AUTO_NORMAL", "True if automatic normal generation enabled", "eval", GL_IS_ENABLED),
new GLproperty(GL11.GL_AUX_BUFFERS, "GL_AUX_BUFFERS", "Number of auxiliary buffers", "capability", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_BLEND, "GL_BLEND", "Blending enabled", "color-buffer/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_BLEND_DST, "GL_BLEND_DST", "Blending destination function", "color-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_BLEND_SRC, "GL_BLEND_SRC", "Blending source function", "color-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_BLUE_BITS, "GL_BLUE_BITS", "Number of bits per blue component in color buffers", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH, "GL_CLIENT_ATTRIB_STACK_DEPTH", "Client attribute stack pointer", "current", GL_GET_INTEGERV),
new GLproperty(GL11.GL_COEFF, "GL_COEFF", "1D control points", "capability", "glGetMapfv()"),
new GLproperty(GL11.GL_COEFF, "GL_COEFF", "2D control points", "capability", "glGetMapfv()"),
new GLproperty(GL11.GL_COLOR_ARRAY, "GL_COLOR_ARRAY", "RGBA color array enable", "vertex-array", GL_IS_ENABLED),
new GLproperty(GL11.GL_COLOR_ARRAY_POINTER, "GL_COLOR_ARRAY_POINTER", "Pointer to the color array", "vertex-array", "glGetPointerv()"),
new GLproperty(GL11.GL_COLOR_ARRAY_SIZE, "GL_COLOR_ARRAY_SIZE", "Colors per vertex", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_COLOR_ARRAY_STRIDE, "GL_COLOR_ARRAY_STRIDE", "Stride between colors", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_COLOR_ARRAY_TYPE, "GL_COLOR_ARRAY_TYPE", "Type of color components", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_COLOR_CLEAR_VALUE, "GL_COLOR_CLEAR_VALUE", "Color-buffer clear value (RGBA mode)", "color-buffer", GL_GET_FLOATV),
new GLproperty(GL11.GL_COLOR_INDEXES, "GL_COLOR_INDEXES", "ca, cd, and cs for color-index lighting", "lighting/e nable", "glGetMaterialfv()"),
new GLproperty(GL11.GL_COLOR_LOGIC_OP, "GL_COLOR_LOGIC_OP", "RGBA color logical operation enabled", "color-buffer/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_COLOR_MATERIAL, "GL_COLOR_MATERIAL", "True if color tracking is enabled", "lighting", GL_IS_ENABLED),
new GLproperty(GL11.GL_COLOR_MATERIAL_FACE, "GL_COLOR_MATERIAL_FACE", "Face(s) affected by color tracking", "lighting", GL_GET_INTEGERV),
new GLproperty(GL11.GL_COLOR_MATERIAL_PARAMETER, "GL_COLOR_MATERIAL_PARAMETER", "Material properties tracking current color", "lighting", GL_GET_INTEGERV),
new GLproperty(GL11.GL_COLOR_WRITEMASK, "GL_COLOR_WRITEMASK", "Color write enables; R, G, B, or A", "color-buffer", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_CONSTANT_ATTENUATION, "GL_CONSTANT_ATTENUATION", "Constant attenuation factor", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_CULL_FACE, "GL_CULL_FACE", "Polygon culling enabled", "polygon/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_CULL_FACE_MODE, "GL_CULL_FACE_MODE", "Cull front-/back-facing polygons", "polygon", GL_GET_INTEGERV),
new GLproperty(GL11.GL_CURRENT_COLOR, "GL_CURRENT_COLOR", "Current color", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_INDEX, "GL_CURRENT_INDEX", "Current color index", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_NORMAL, "GL_CURRENT_NORMAL", "Current normal", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_RASTER_COLOR, "GL_CURRENT_RASTER_COLOR", "Color associated with raster position", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_RASTER_DISTANCE, "GL_CURRENT_RASTER_DISTANCE", "Current raster distance", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_RASTER_INDEX, "GL_CURRENT_RASTER_INDEX", "Color index associated with raster position", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_RASTER_POSITION, "GL_CURRENT_RASTER_POSITION", "Current raster position", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_RASTER_POSITION_VALID, "GL_CURRENT_RASTER_POSITION_VALID", "Raster position valid bit", "current", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_CURRENT_RASTER_TEXTURE_COORDS, "GL_CURRENT_RASTER_TEXTURE_COORDS", "Texture coordinates associated with raster position", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_CURRENT_TEXTURE_COORDS, "GL_CURRENT_TEXTURE_COORDS", "Current texture coordinates", "current", GL_GET_FLOATV),
new GLproperty(GL11.GL_DEPTH_BITS, "GL_DEPTH_BITS", "Number of depth-buffer bitplanes", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_DEPTH_CLEAR_VALUE, "GL_DEPTH_CLEAR_VALUE", "Depth-buffer clear value", "depth-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_DEPTH_FUNC, "GL_DEPTH_FUNC", "Depth buffer test function", "depth-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_DEPTH_RANGE, "GL_DEPTH_RANGE", "Depth range near and far", "viewport", GL_GET_FLOATV),
new GLproperty(GL11.GL_DEPTH_TEST, "GL_DEPTH_TEST", "Depth buffer enabled", "depth-buffer/ena ble", GL_IS_ENABLED),
new GLproperty(GL11.GL_DEPTH_WRITEMASK, "GL_DEPTH_WRITEMASK", "Depth buffer enabled for writing", "depth-buffer", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_DIFFUSE, "GL_DIFFUSE", "Diffuse intensity of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_DIFFUSE, "GL_DIFFUSE", "Diffuse material color", "lighting", "glGetMaterialfv()"),
new GLproperty(GL11.GL_DITHER, "GL_DITHER", "Dithering enabled", "color-buffer/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_DOMAIN, "GL_DOMAIN", "1D domain endpoints", "capability", "glGetMapfv()"),
new GLproperty(GL11.GL_DOMAIN, "GL_DOMAIN", "2D domain endpoints", "capability", "glGetMapfv()"),
new GLproperty(GL11.GL_DOUBLEBUFFER, "GL_DOUBLEBUFFER", "True if front and back buffers exist", "capability", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_DRAW_BUFFER, "GL_DRAW_BUFFER", "Buffers selected for drawing", "color-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_EDGE_FLAG, "GL_EDGE_FLAG", "Edge flag", "current", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_EDGE_FLAG_ARRAY, "GL_EDGE_FLAG_ARRAY", "Edge flag array enable", "vertex-array", GL_IS_ENABLED),
new GLproperty(GL11.GL_EDGE_FLAG_ARRAY_POINTER, "GL_EDGE_FLAG_ARRAY_POINTER", "Pointer to the edge flag array", "vertex-array", "glGetPointerv()"),
new GLproperty(GL11.GL_EDGE_FLAG_ARRAY_STRIDE, "GL_EDGE_FLAG_ARRAY_STRIDE", "Stride between edge flags", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_EMISSION, "GL_EMISSION", "Emissive material color", "lighting", "glGetMaterialfv()"),
new GLproperty(GL11.GL_EYE_PLANE, "GL_EYE_PLANE", "Texgen plane equation coefficients", "texture", "glGetTexGenfv()"),
new GLproperty(GL11.GL_FEEDBACK_BUFFER_POINTER, "GL_FEEDBACK_BUFFER_POINTER", "Pointer to feedback buffer", "feedback", "glGetPointerv()"),
new GLproperty(GL11.GL_FEEDBACK_BUFFER_SIZE, "GL_FEEDBACK_BUFFER_SIZE", "Size of feedback buffer", "feedback", GL_GET_INTEGERV),
new GLproperty(GL11.GL_FEEDBACK_BUFFER_TYPE, "GL_FEEDBACK_BUFFER_TYPE", "Type of feedback buffer", "feedback", GL_GET_INTEGERV),
new GLproperty(GL11.GL_FOG, "GL_FOG", "True if fog enabled", "fog/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_FOG_COLOR, "GL_FOG_COLOR", "Fog color", "fog", GL_GET_FLOATV),
new GLproperty(GL11.GL_FOG_DENSITY, "GL_FOG_DENSITY", "Exponential fog density", "fog", GL_GET_FLOATV),
new GLproperty(GL11.GL_FOG_END, "GL_FOG_END", "Linear fog end", "fog", GL_GET_FLOATV),
new GLproperty(GL11.GL_FOG_HINT, "GL_FOG_HINT", "Fog hint", "hint", GL_GET_INTEGERV),
new GLproperty(GL11.GL_FOG_INDEX, "GL_FOG_INDEX", "Fog index", "fog", GL_GET_FLOATV),
new GLproperty(GL11.GL_FOG_MODE, "GL_FOG_MODE", "Fog mode", "fog", GL_GET_INTEGERV),
new GLproperty(GL11.GL_FOG_START, "GL_FOG_START", "Linear fog start", "fog", GL_GET_FLOATV),
new GLproperty(GL11.GL_FRONT_FACE, "GL_FRONT_FACE", "Polygon front-face CW/CCW indicator", "polygon", GL_GET_INTEGERV),
new GLproperty(GL11.GL_GREEN_BITS, "GL_GREEN_BITS", "Number of bits per green component in color buffers", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_INDEX_ARRAY, "GL_INDEX_ARRAY", "Color-index array enable", "vertex-array", GL_IS_ENABLED),
new GLproperty(GL11.GL_INDEX_ARRAY_POINTER, "GL_INDEX_ARRAY_POINTER", "Pointer to the index array", "vertex-array", "glGetPointerv()"),
new GLproperty(GL11.GL_INDEX_ARRAY_STRIDE, "GL_INDEX_ARRAY_STRIDE", "Stride between color indices", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_INDEX_ARRAY_TYPE, "GL_INDEX_ARRAY_TYPE", "Type of color indices", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_INDEX_BITS, "GL_INDEX_BITS", "Number of bits per index in color buffers", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_INDEX_CLEAR_VALUE, "GL_INDEX_CLEAR_VALUE", "Color-buffer clear value (color-index mode)", "color-buffer", GL_GET_FLOATV),
new GLproperty(GL11.GL_INDEX_LOGIC_OP, "GL_INDEX_LOGIC_OP", "Color index logical operation enabled", "color-buffer/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_INDEX_MODE, "GL_INDEX_MODE", "True if color buffers store indices", "capability", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_INDEX_OFFSET, "GL_INDEX_OFFSET", "Value of GL_INDEX_OFFSET", "pixel", GL_GET_INTEGERV),
new GLproperty(GL11.GL_INDEX_SHIFT, "GL_INDEX_SHIFT", "Value of GL_INDEX_SHIFT", "pixel", GL_GET_INTEGERV),
new GLproperty(GL11.GL_INDEX_WRITEMASK, "GL_INDEX_WRITEMASK", "Color-index writemask", "color-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LIGHT0, "GL_LIGHT0", "True if light 0 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT1, "GL_LIGHT1", "True if light 1 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT2, "GL_LIGHT2", "True if light 2 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT3, "GL_LIGHT3", "True if light 3 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT4, "GL_LIGHT4", "True if light 4 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT5, "GL_LIGHT5", "True if light 5 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT6, "GL_LIGHT6", "True if light 6 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT7, "GL_LIGHT7", "True if light 7 enabled", "lighting/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHTING, "GL_LIGHTING", "True if lighting is enabled", "lighting/e nable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LIGHT_MODEL_AMBIENT, "GL_LIGHT_MODEL_AMBIENT", "Ambient scene color", "lighting", GL_GET_FLOATV),
new GLproperty(GL11.GL_LIGHT_MODEL_LOCAL_VIEWER, "GL_LIGHT_MODEL_LOCAL_VIEWER", "Viewer is local", "lighting", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_LIGHT_MODEL_TWO_SIDE, "GL_LIGHT_MODEL_TWO_SIDE", "Use two-sided lighting", "lighting", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_LINEAR_ATTENUATION, "GL_LINEAR_ATTENUATION", "Linear attenuation factor", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_LINE_SMOOTH, "GL_LINE_SMOOTH", "Line antialiasing on", "line/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LINE_SMOOTH_HINT, "GL_LINE_SMOOTH_HINT", "Line smooth hint", "hint", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LINE_STIPPLE, "GL_LINE_STIPPLE", "Line stipple enable", "line/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_LINE_STIPPLE_PATTERN, "GL_LINE_STIPPLE_PATTERN", "Line stipple", "line", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LINE_STIPPLE_REPEAT, "GL_LINE_STIPPLE_REPEAT", "Line stipple repeat", "line", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LINE_WIDTH, "GL_LINE_WIDTH", "Line width", "line", GL_GET_FLOATV),
new GLproperty(GL11.GL_LINE_WIDTH_GRANULARITY, "GL_LINE_WIDTH_GRANULARITY", "Antialiased line-width granularity", "capability", GL_GET_FLOATV),
new GLproperty(GL11.GL_LINE_WIDTH_RANGE, "GL_LINE_WIDTH_RANGE", "Range (low to high) of antialiased line widths", "capability", GL_GET_FLOATV),
new GLproperty(GL11.GL_LIST_BASE, "GL_LIST_BASE", "Setting of glListBase()", "list", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LIST_INDEX, "GL_LIST_INDEX", "Number of display list under construction; 0 if none", "current", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LIST_MODE, "GL_LIST_MODE", "Mode of display list under construction; undefined if none", "current", GL_GET_INTEGERV),
new GLproperty(GL11.GL_LOGIC_OP_MODE, "GL_LOGIC_OP_MODE", "Logical operation function", "color-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAP1_GRID_DOMAIN, "GL_MAP1_GRID_DOMAIN", "1D grid endpoints", "eval", GL_GET_FLOATV),
new GLproperty(GL11.GL_MAP1_GRID_SEGMENTS, "GL_MAP1_GRID_SEGMENTS", "1D grid divisions", "eval", GL_GET_FLOATV),
new GLproperty(GL11.GL_MAP2_GRID_DOMAIN, "GL_MAP2_GRID_DOMAIN", "2D grid endpoints", "eval", GL_GET_FLOATV),
new GLproperty(GL11.GL_MAP2_GRID_SEGMENTS, "GL_MAP2_GRID_SEGMENTS", "2D grid divisions", "eval", GL_GET_FLOATV),
new GLproperty(GL11.GL_MAP_COLOR, "GL_MAP_COLOR", "True if colors are mapped", "pixel", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_MAP_STENCIL, "GL_MAP_STENCIL", "True if stencil values are mapped", "pixel", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_MATRIX_MODE, "GL_MATRIX_MODE", "Current matrix mode", "transform", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH", "Maximum depth of the attribute stack", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH", "Maximum depth of the client attribute stack", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES", "Maximum number of user clipping planes", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER", "Maximum evaluator polynomial order", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_LIGHTS, "GL_MAX_LIGHTS", "Maximum number of lights", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING", "Maximum display-list call nesting", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH", "Maximum modelview-matrix stack depth", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH", "Maximum selection-name stack depth", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE", "Maximum size of a glPixelMap() translation table", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH", "Maximum projection-matrix stack depth", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE", "See discussion in Texture Proxy in Chapter 9", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH", "Maximum depth of texture matrix stack", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS", "Maximum viewport dimensions", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_MODELVIEW_MATRIX, "GL_MODELVIEW_MATRIX", "Modelview matrix stack", "matrix", GL_GET_FLOATV),
new GLproperty(GL11.GL_MODELVIEW_STACK_DEPTH, "GL_MODELVIEW_STACK_DEPTH", "Modelview matrix stack pointer", "matrix", GL_GET_INTEGERV),
new GLproperty(GL11.GL_NAME_STACK_DEPTH, "GL_NAME_STACK_DEPTH", "Name stack depth", "current", GL_GET_INTEGERV),
new GLproperty(GL11.GL_NORMALIZE, "GL_NORMALIZE", "Current normal normalization on/off", "transform/ enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_NORMAL_ARRAY, "GL_NORMAL_ARRAY", "Normal array enable", "vertex-array", GL_IS_ENABLED),
new GLproperty(GL11.GL_NORMAL_ARRAY_POINTER, "GL_NORMAL_ARRAY_POINTER", "Pointer to the normal array", "vertex-array", "glGetPointerv()"),
new GLproperty(GL11.GL_NORMAL_ARRAY_STRIDE, "GL_NORMAL_ARRAY_STRIDE", "Stride between normals", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_NORMAL_ARRAY_TYPE, "GL_NORMAL_ARRAY_TYPE", "Type of normal coordinates", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_OBJECT_PLANE, "GL_OBJECT_PLANE", "Texgen object linear coefficients", "texture", "glGetTexGenfv()"),
new GLproperty(GL11.GL_ORDER, "GL_ORDER", "1D map order", "capability", "glGetMapiv()"),
new GLproperty(GL11.GL_ORDER, "GL_ORDER", "2D map orders", "capability", "glGetMapiv()"),
new GLproperty(GL11.GL_PACK_ALIGNMENT, "GL_PACK_ALIGNMENT", "Value of GL_PACK_ALIGNMENT", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_PACK_LSB_FIRST, "GL_PACK_LSB_FIRST", "Value of GL_PACK_LSB_FIRST", "pixel-store", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_PACK_ROW_LENGTH, "GL_PACK_ROW_LENGTH", "Value of GL_PACK_ROW_LENGTH", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_PACK_SKIP_PIXELS, "GL_PACK_SKIP_PIXELS", "Value of GL_PACK_SKIP_PIXELS", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_PACK_SKIP_ROWS, "GL_PACK_SKIP_ROWS", "Value of GL_PACK_SKIP_ROWS", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_PACK_SWAP_BYTES, "GL_PACK_SWAP_BYTES", "Value of GL_PACK_SWAP_BYTES", "pixel-store", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_PERSPECTIVE_CORRECTION_HINT, "GL_PERSPECTIVE_CORRECTION_HINT", "Perspective correction hint", "hint", GL_GET_INTEGERV),
new GLproperty(GL11.GL_POINT_SIZE, "GL_POINT_SIZE", "Point size", "point", GL_GET_FLOATV),
new GLproperty(GL11.GL_POINT_SIZE_GRANULARITY, "GL_POINT_SIZE_GRANULARITY", "Antialiased point-size granularity", "capability", GL_GET_FLOATV),
new GLproperty(GL11.GL_POINT_SIZE_RANGE, "GL_POINT_SIZE_RANGE", "Range (low to high) of antialiased point sizes", "capability", GL_GET_FLOATV),
new GLproperty(GL11.GL_POINT_SMOOTH, "GL_POINT_SMOOTH", "Point antialiasing on", "point/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_POINT_SMOOTH_HINT, "GL_POINT_SMOOTH_HINT", "Point smooth hint", "hint", GL_GET_INTEGERV),
new GLproperty(GL11.GL_POLYGON_MODE, "GL_POLYGON_MODE", "Polygon rasterization mode (front and back)", "polygon", GL_GET_INTEGERV),
new GLproperty(GL11.GL_POLYGON_OFFSET_FACTOR, "GL_POLYGON_OFFSET_FACTOR", "Polygon offset factor", "polygon", GL_GET_FLOATV),
new GLproperty(GL11.GL_POLYGON_OFFSET_FILL, "GL_POLYGON_OFFSET_FILL", "Polygon offset enable for GL_FILL mode rasterization", "polygon/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_POLYGON_OFFSET_LINE, "GL_POLYGON_OFFSET_LINE", "Polygon offset enable for GL_LINE mode rasterization", "polygon/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_POLYGON_OFFSET_POINT, "GL_POLYGON_OFFSET_POINT", "Polygon offset enable for GL_POINT mode rasterization", "polygon/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_POLYGON_SMOOTH, "GL_POLYGON_SMOOTH", "Polygon antialiasing on", "polygon/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_POLYGON_SMOOTH_HINT, "GL_POLYGON_SMOOTH_HINT", "Polygon smooth hint", "hint", GL_GET_INTEGERV),
new GLproperty(GL11.GL_POLYGON_STIPPLE, "GL_POLYGON_STIPPLE", "Polygon stipple enable", "polygon/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_POSITION, "GL_POSITION", "Position of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_PROJECTION_MATRIX, "GL_PROJECTION_MATRIX", "Projection matrix stack", "matrix", GL_GET_FLOATV),
new GLproperty(GL11.GL_PROJECTION_STACK_DEPTH, "GL_PROJECTION_STACK_DEPTH", "Projection matrix stack pointer", "matrix", GL_GET_INTEGERV),
new GLproperty(GL11.GL_QUADRATIC_ATTENUATION, "GL_QUADRATIC_ATTENUATION", "Quadratic attenuation factor", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_READ_BUFFER, "GL_READ_BUFFER", "Read source buffer", "pixel", GL_GET_INTEGERV),
new GLproperty(GL11.GL_RED_BITS, "GL_RED_BITS", "Number of bits per red component in color buffers", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_RENDER_MODE, "GL_RENDER_MODE", "glRenderMode() setting", "current", GL_GET_INTEGERV),
new GLproperty(GL11.GL_RGBA_MODE, "GL_RGBA_MODE", "True if color buffers store RGBA", "capability", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_SCISSOR_BOX, "GL_SCISSOR_BOX", "Scissor box", "scissor", GL_GET_INTEGERV),
new GLproperty(GL11.GL_SCISSOR_TEST, "GL_SCISSOR_TEST", "Scissoring enabled", "scissor/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_SELECTION_BUFFER_POINTER, "GL_SELECTION_BUFFER_POINTER", "Pointer to selection buffer", "select", "glGetPointerv()"),
new GLproperty(GL11.GL_SELECTION_BUFFER_SIZE, "GL_SELECTION_BUFFER_SIZE", "Size of selection buffer", "select", GL_GET_INTEGERV),
new GLproperty(GL11.GL_SHADE_MODEL, "GL_SHADE_MODEL", "glShadeModel() setting", "lighting", GL_GET_INTEGERV),
new GLproperty(GL11.GL_SHININESS, "GL_SHININESS", "Specular exponent of material", "lighting", "glGetMaterialfv()"),
new GLproperty(GL11.GL_SPECULAR, "GL_SPECULAR", "Specular intensity of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_SPECULAR, "GL_SPECULAR", "Specular material color", "lighting", "glGetMaterialfv()"),
new GLproperty(GL11.GL_SPOT_CUTOFF, "GL_SPOT_CUTOFF", "Spotlight angle of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_SPOT_DIRECTION, "GL_SPOT_DIRECTION", "Spotlight direction of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_SPOT_EXPONENT, "GL_SPOT_EXPONENT", "Spotlight exponent of light i", "lighting", "glGetLightfv()"),
new GLproperty(GL11.GL_STENCIL_BITS, "GL_STENCIL_BITS", "Number of stencil bitplanes", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_CLEAR_VALUE, "GL_STENCIL_CLEAR_VALUE", "Stencil-buffer clear value", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_FAIL, "GL_STENCIL_FAIL", "Stencil fail action", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_FUNC, "GL_STENCIL_FUNC", "Stencil function", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_PASS_DEPTH_FAIL, "GL_STENCIL_PASS_DEPTH_FAIL", "Stencil depth buffer fail action", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_PASS_DEPTH_PASS, "GL_STENCIL_PASS_DEPTH_PASS", "Stencil depth buffer pass action", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_REF, "GL_STENCIL_REF", "Stencil reference value", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_TEST, "GL_STENCIL_TEST", "Stenciling enabled", "stencil-buffer/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_STENCIL_VALUE_MASK, "GL_STENCIL_VALUE_MASK", "Stencil mask", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STENCIL_WRITEMASK, "GL_STENCIL_WRITEMASK", "Stencil-buffer writemask", "stencil-buffer", GL_GET_INTEGERV),
new GLproperty(GL11.GL_STEREO, "GL_STEREO", "True if left and right buffers exist", "capability", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_SUBPIXEL_BITS, "GL_SUBPIXEL_BITS", "Number of bits of subpixel precision in x and y", "capability", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE, "GL_TEXTURE", "x-D texture image at level of detail i", "UNUSED", "glGetTexImage()"),
new GLproperty(GL11.GL_TEXTURE_1D, "GL_TEXTURE_1D", "True if 1-D texturing enabled ", "texture/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_2D, "GL_TEXTURE_2D", "True if 2-D texturing enabled ", "texture/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_ALPHA_SIZE, "GL_TEXTURE_ALPHA_SIZE", "x-D texture image i's alpha resolution", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_BINDING_1D, "GL_TEXTURE_BINDING_1D", "Texture object bound to GL_TEXTURE_1D", "texture", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE_BINDING_2D, "GL_TEXTURE_BINDING_2D", "Texture object bound to GL_TEXTURE_2D", "texture", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE_BLUE_SIZE, "GL_TEXTURE_BLUE_SIZE", "x-D texture image i's blue resolution", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_BORDER, "GL_TEXTURE_BORDER", "x-D texture image i's border width", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_BORDER_COLOR, "GL_TEXTURE_BORDER_COLOR", "Texture border color", "texture", "glGetTexParameter*()"),
new GLproperty(GL11.GL_TEXTURE_COORD_ARRAY, "GL_TEXTURE_COORD_ARRAY", "Texture coordinate array enable", "vertex-array", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_COORD_ARRAY_POINTER, "GL_TEXTURE_COORD_ARRAY_POINTER", "Pointer to the texture coordinate array", "vertex-array", "glGetPointerv()"),
new GLproperty(GL11.GL_TEXTURE_COORD_ARRAY_SIZE, "GL_TEXTURE_COORD_ARRAY_SIZE", "Texture coordinates per element", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE_COORD_ARRAY_STRIDE, "GL_TEXTURE_COORD_ARRAY_STRIDE", "Stride between texture coordinates", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE_COORD_ARRAY_TYPE, "GL_TEXTURE_COORD_ARRAY_TYPE", "Type of texture coordinates", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE_ENV_COLOR, "GL_TEXTURE_ENV_COLOR", "Texture environment color", "texture", "glGetTexEnvfv()"),
new GLproperty(GL11.GL_TEXTURE_ENV_MODE, "GL_TEXTURE_ENV_MODE", "Texture application function", "texture", "glGetTexEnviv()"),
new GLproperty(GL11.GL_TEXTURE_GEN_MODE, "GL_TEXTURE_GEN_MODE", "Function used for texgen", "texture", "glGetTexGeniv()"),
new GLproperty(GL11.GL_TEXTURE_GEN_Q, "GL_TEXTURE_GEN_Q", "Texgen enabled (x is S, T, R, or Q)", "texture/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_GEN_R, "GL_TEXTURE_GEN_R", "Texgen enabled (x is S, T, R, or Q)", "texture/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_GEN_S, "GL_TEXTURE_GEN_S", "Texgen enabled (x is S, T, R, or Q)", "texture/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_GEN_T, "GL_TEXTURE_GEN_T", "Texgen enabled (x is S, T, R, or Q)", "texture/enable", GL_IS_ENABLED),
new GLproperty(GL11.GL_TEXTURE_GREEN_SIZE, "GL_TEXTURE_GREEN_SIZE", "x-D texture image i's green resolution", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_HEIGHT, "GL_TEXTURE_HEIGHT", "x-D texture image i's height", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_INTENSITY_SIZE, "GL_TEXTURE_INTENSITY_SIZE", "x-D texture image i's intensity resolution", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_LUMINANCE_SIZE, "GL_TEXTURE_LUMINANCE_SIZE", "x-D texture image i's luminance resolution", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_MAG_FILTER, "GL_TEXTURE_MAG_FILTER", "Texture magnification function", "texture", "glGetTexParameter*()"),
new GLproperty(GL11.GL_TEXTURE_MATRIX, "GL_TEXTURE_MATRIX", "Texture matrix stack", "matrix", GL_GET_FLOATV),
new GLproperty(GL11.GL_TEXTURE_MIN_FILTER, "GL_TEXTURE_MIN_FILTER", "Texture minification function", "texture", "glGetTexParameter*()"),
new GLproperty(GL11.GL_TEXTURE_PRIORITY, "GL_TEXTURE_PRIORITY", "Texture object priority", "texture", "glGetTexParameter*()"),
new GLproperty(GL11.GL_TEXTURE_RED_SIZE, "GL_TEXTURE_RED_SIZE", "x-D texture image i's red resolution", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_STACK_DEPTH, "GL_TEXTURE_STACK_DEPTH", "Texture matrix stack pointer", "matrix", GL_GET_INTEGERV),
new GLproperty(GL11.GL_TEXTURE_WIDTH, "GL_TEXTURE_WIDTH", "x-D texture image i's width", "UNUSED", "glGetTexLevelParameter*()"),
new GLproperty(GL11.GL_TEXTURE_WRAP_S, "GL_TEXTURE_WRAP_S", "Texture wrap mode (x is S or T)", "texture", "glGetTexParameter*()"),
new GLproperty(GL11.GL_TEXTURE_WRAP_T, "GL_TEXTURE_WRAP_T", "Texture wrap mode (x is S or T)", "texture", "glGetTexParameter*()"),
new GLproperty(GL11.GL_UNPACK_ALIGNMENT, "GL_UNPACK_ALIGNMENT", "Value of GL_UNPACK_ALIGNMENT", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_UNPACK_LSB_FIRST, "GL_UNPACK_LSB_FIRST", "Value of GL_UNPACK_LSB_FIRST", "pixel-store", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_UNPACK_ROW_LENGTH, "GL_UNPACK_ROW_LENGTH", "Value of GL_UNPACK_ROW_LENGTH", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_UNPACK_SKIP_PIXELS, "GL_UNPACK_SKIP_PIXELS", "Value of GL_UNPACK_SKIP_PIXELS", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_UNPACK_SKIP_ROWS, "GL_UNPACK_SKIP_ROWS", "Value of GL_UNPACK_SKIP_ROWS", "pixel-store", GL_GET_INTEGERV),
new GLproperty(GL11.GL_UNPACK_SWAP_BYTES, "GL_UNPACK_SWAP_BYTES", "Value of GL_UNPACK_SWAP_BYTES", "pixel-store", GL_GET_BOOLEANV),
new GLproperty(GL11.GL_VERTEX_ARRAY, "GL_VERTEX_ARRAY", "Vertex array enable", "vertex-array", GL_IS_ENABLED),
new GLproperty(GL11.GL_VERTEX_ARRAY_POINTER, "GL_VERTEX_ARRAY_POINTER", "Pointer to the vertex array", "vertex-array", "glGetPointerv()"),
new GLproperty(GL11.GL_VERTEX_ARRAY_SIZE, "GL_VERTEX_ARRAY_SIZE", "Coordinates per vertex", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_VERTEX_ARRAY_STRIDE, "GL_VERTEX_ARRAY_STRIDE", "Stride between vertices", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_VERTEX_ARRAY_TYPE, "GL_VERTEX_ARRAY_TYPE", "Type of vertex coordinates", "vertex-array", GL_GET_INTEGERV),
new GLproperty(GL11.GL_VIEWPORT, "GL_VIEWPORT", "Viewport origin and extent", "viewport", GL_GET_INTEGERV),
new GLproperty(GL11.GL_ZOOM_X, "GL_ZOOM_X", "x zoom factor", "pixel", GL_GET_FLOATV),
new GLproperty(GL11.GL_ZOOM_Y, "GL_ZOOM_Y", "y zoom factor", "pixel", GL_GET_FLOATV),
};
public static void dumpToFile(Consumer<Consumer<String>> dumper, String fileName) {
final List<String> lines = new ArrayList<>();
dumper.accept(lines::add);
try {
FileUtils.writeLines(new File(fileName), lines);
} catch (IOException e) {
LOGGER.error("Failed to write file");
e.printStackTrace();
}
}
public static void dumpStateToFile() {
dumpToFile(p -> dumpState(p, false), "gl-dump-state.txt");
}
public static void dumpGLSMStateToFile() {
dumpToFile(p -> dumpState(p, true), "glsm-dump-state.txt");
}
public static void dumpState(boolean glsm) {
dumpState(LINE_LOGGER, glsm);
}
public static void dumpState(Consumer<String> printer, boolean glsm) {
for (int i = 0; i < instance.propertyList.length; ++i) {
final GLproperty gLProperty = instance.propertyList[i];
printer.accept(gLProperty.name + ":" + gLProperty.getAsString(glsm) + " (" + gLProperty.description + ")");
}
}
public static void dumpIsEnabledToFile(boolean glsm) {
dumpToFile(p -> dumpIsEnabled(p, glsm), (glsm ? "glsm" : "gl") + "-dump-enabled.txt");
}
public static void dumpIsEnabled(boolean glsm) {
dumpIsEnabled(LINE_LOGGER, glsm);
}
public static void dumpIsEnabled(Consumer<String> printer, boolean glsm) {
for (int i = 0; i < instance.propertyList.length; ++i) {
final GLproperty gLProperty = instance.propertyList[i];
if (gLProperty.fetchCommand.equals(GL_IS_ENABLED)) {
printer.accept(gLProperty.name + ":");
printer.accept("" + gLProperty.getAsString(glsm));
printer.accept(" (" + gLProperty.description + ")");
}
}
}
public static void dumpTypeToFile(String type, boolean glsm) {
dumpToFile(p -> dumpType(type, p, glsm), (glsm ? "glsm" : "gl") + "-dump-type-" + type + ".txt");
}
public static void dumpType(String type, boolean glsm) {
dumpType(type, LINE_LOGGER, glsm);
}
public static void dumpType(String type, Consumer<String> printer, boolean glsm) {
for (int i = 0; i < instance.propertyList.length; ++i) {
final GLproperty gLProperty = instance.propertyList[i];
if (gLProperty.category.equals(type)) {
printer.accept(gLProperty.name + ":");
printer.accept(gLProperty.getAsString(glsm));
printer.accept(" (" + gLProperty.description + ")");
}
}
}
public static String getGLSMErrorLog() {
return getGLSMErrorLog(null, false, false);
}
// Re-entrancy guard - getGLSMErrorLog calls glActiveTexture which could trigger checkGLSMOnce
private static boolean inCheck = false;
/**
* Enhanced GLSM error logging with context, stack trace, and first-occurrence filtering.
*
* @param context Optional context string to include in error messages (e.g., "During rendering")
* @param logStacktrace If true, includes the current stack trace in the error output
* @param onlyFirstOccurrence If true, only logs each unique error once
* @return Error log string if mismatches found, null otherwise
*/
public static String getGLSMErrorLog(String context, boolean logStacktrace, boolean onlyFirstOccurrence) {
if (inCheck) return null;
if (!GLStateManager.isCachingEnabled() || GLStateManager.isRecordingDisplayList()) {
return null;
}
inCheck = true;
try {
String group = "checkGLSM" + (context == null ? "" : " " + context);
GLDebug.pushGroup(group);
final StringBuilder error = new StringBuilder();
boolean mismatch = false;
if (context != null && !context.isEmpty()) {
error.append("[").append(context).append("] ");
}
for (int i = 0; i < instance.propertyList.length; ++i) {
final GLproperty gLProperty = instance.propertyList[i];
if (gLProperty.fetchCommand.equals(GL_GET_FLOATV) && gLProperty.name.endsWith("_MATRIX")) {
final Matrix4f cached = gLProperty.getAsMatrix4f(true);
final Matrix4f uncached = gLProperty.getAsMatrix4f(false);
// Skip comparison if either matrix is degenerate (contains NaN/Infinity) these represent invalid GL state from bad parameters, not cache bugs
if (isMatrixDegenerate(cached) || isMatrixDegenerate(uncached)) continue;
if (!matricesEquivalent(cached, uncached, 0.001f)) {
final String errorKey = "MATRIX:" + gLProperty.name;
if (!onlyFirstOccurrence || seenErrors.add(errorKey)) {
final String errorMsg = "GLSM mismatch: " + gLProperty.name + "\ncached:\n" + cached + "uncached:\n" + uncached;
LOGGER.error(errorMsg);
error.append(errorMsg).append('\n');
mismatch = true;
}
}
} else {
final String cached = gLProperty.getAsString(true);
final String uncached = gLProperty.getAsString(false);
if (!cached.equals(uncached)) {
final String errorKey = "PROPERTY:" + gLProperty.name + ":" + cached + ":" + uncached;
if (!onlyFirstOccurrence || seenErrors.add(errorKey)) {
error.append("GLSM mismatch: ").append(gLProperty.name).append(" cached: ").append(cached).append(" uncached: ").append(uncached);
error.append('\n');
mismatch = true;
}
}
}
}
final TextureUnitArray textureUnits = GLStateManager.getTextures();
final int currentActiveTexture = GLStateManager.getActiveTextureUnit();
// Check GL_ACTIVE_TEXTURE
final int glActiveUnit = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE) - GL13.GL_TEXTURE0;
if (glActiveUnit != currentActiveTexture) {
final String errorKey = "ACTIVE_TEXTURE:" + currentActiveTexture + ":" + glActiveUnit;
if (!onlyFirstOccurrence || seenErrors.add(errorKey)) {
error.append("GLSM mismatch: GL_ACTIVE_TEXTURE cached: ").append(currentActiveTexture)
.append(" uncached: ").append(glActiveUnit).append('\n');
mismatch = true;
}
}
// Check per-unit texture state
for (int i = 0; i < textureUnits.textureMatricies.length; i++) {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + i);
// Check GL_TEXTURE_2D enabled
final boolean cachedEnabled = textureUnits.getTextureUnitStates(i).isEnabled();
final boolean uncachedEnabled = GL11.glIsEnabled(GL11.GL_TEXTURE_2D);
if (cachedEnabled != uncachedEnabled) {
final String errorKey = "TEXTURE_2D:" + i + ":" + cachedEnabled + ":" + uncachedEnabled;
if (!onlyFirstOccurrence || seenErrors.add(errorKey)) {
error.append("GLSM mismatch: GL_TEXTURE_2D cached: ").append(cachedEnabled)
.append(" uncached: ").append(uncachedEnabled)
.append(", texture unit: GL_TEXTURE").append(i).append('\n');
mismatch = true;
}
}
// Check GL_TEXTURE_BINDING_2D
final int cachedBinding = textureUnits.getTextureUnitBindings(i).getBinding();
final int uncachedBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
if (cachedBinding != uncachedBinding) {
final String errorKey = "TEXTURE_BINDING_2D:" + i + ":" + cachedBinding + ":" + uncachedBinding;
if (!onlyFirstOccurrence || seenErrors.add(errorKey)) {
error.append("GLSM mismatch: GL_TEXTURE_BINDING_2D cached: ").append(cachedBinding)
.append(" uncached: ").append(uncachedBinding)
.append(", texture unit: GL_TEXTURE").append(i).append('\n');
mismatch = true;
}
}
}
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + currentActiveTexture);
// Add stack trace if requested
if (mismatch && logStacktrace) {
error.append("\nStack trace:\n");
final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (int i = 2; i < stackTrace.length; i++) {
error.append(" at ").append(stackTrace[i].toString()).append('\n');
}
}
GLDebug.popGroup();
return mismatch ? error.toString() : null;
} finally {
inCheck = false;
}
}
public static boolean checkGLSMOnce(String context) {
final String output = getGLSMErrorLog(context, true, true);
if (output != null) {
// Only log on actual mismatch
LOGGER.error("[{}] MISMATCH thread={}\n{}", context, Thread.currentThread().getName(), output);
return false;
}
return true;
}
/**
* Check if a matrix contains any non-finite values (NaN or Infinity).
* Such matrices represent invalid/degenerate GL state (e.g., zero near/far in projection).
*/
private static boolean isMatrixDegenerate(Matrix4f matrix) {
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 4; row++) {
if (!Float.isFinite(matrix.get(col, row))) {
return true;
}
}
}
return false;
}
/**
* Compare two matrices with tolerance for NaN/Infinity.
* Treats NaN == NaN and Infinity == Infinity as equal (both are degenerate states).
* For finite values, uses epsilon comparison.
*/
private static boolean matricesEquivalent(Matrix4f a, Matrix4f b, float epsilon) {
// Compare all 16 elements
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 4; row++) {
final float aVal = a.get(col, row);
final float bVal = b.get(col, row);
// If both are non-finite (NaN or Infinity), consider them equal
if (!Float.isFinite(aVal) && !Float.isFinite(bVal)) {
// Both non-finite: check if both NaN or both same Infinity
if (Float.isNaN(aVal) && Float.isNaN(bVal)) continue;
if (Float.isInfinite(aVal) && Float.isInfinite(bVal)) {
// Check same sign of infinity
if ((aVal > 0) == (bVal > 0)) continue;
}
return false; // Different non-finite values
}
// If one is finite and other is not, they differ
if (Float.isFinite(aVal) != Float.isFinite(bVal)) {
return false;
}
// Both finite: use epsilon comparison
if (Math.abs(aVal - bVal) > epsilon) {
return false;
}
}
}
return true;
}
public static void checkGLSM() {
final String output = getGLSMErrorLog();
if (output == null) {
LOGGER.info("GLSM state matches!");
} else {
LOGGER.error(output);
}
}
public static void copyTexture(ResourceLocation resource, File output) {
final Object object = Minecraft.getMinecraft().renderEngine.mapTextureObjects.get(resource);
if (object != null) {
copyTexture(((ITextureObject) object).getGlTextureId(), output);
}
}
public static void copyTexture(int textureID, File output) {
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH);
int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT);
BufferedImage bufferedimage = new BufferedImage(width, height, 1);
final int[] pixelValues = ((DataBufferInt) bufferedimage.getRaster().getDataBuffer()).getData();
IntBuffer pixelBuffer = BufferUtils.createIntBuffer(pixelValues.length);
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
pixelBuffer.get(pixelValues);
// Flip texture
final int halfHeight = height / 2;
final int[] rowBuffer = new int[width];
for (int y = 0; y < halfHeight; y++) {
final int top = y * width;
final int bottom = (height - 1 - y) * width;
System.arraycopy(pixelValues, top, rowBuffer, 0, width);
System.arraycopy(pixelValues, bottom, pixelValues, top, width);
System.arraycopy(rowBuffer, 0, pixelValues, bottom, width);
}
File dir = output.getParentFile();
dir.mkdirs();
copyBufferedImageToFile(bufferedimage, output);
bufferedimage.flush();
}
private static void copyBufferedImageToFile(BufferedImage image, File file) {
try {
ImageIO.write(image, "png", file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -5,8 +5,6 @@ import com.mitchej123.glsm.RenderSystemService;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import java.nio.FloatBuffer;
public class AngelicaRenderSystemService implements RenderSystemService {
@@ -115,17 +113,17 @@ public class AngelicaRenderSystemService implements RenderSystemService {
@Override
public void glUniform1i(int location, int value) {
GL20.glUniform1i(location, value);
GLStateManager.glUniform1i(location, value);
}
@Override
public void glUniformMatrix3(int location, boolean transpose, FloatBuffer value) {
GL20.glUniformMatrix3(location, transpose, value);
GLStateManager.glUniformMatrix3(location, transpose, value);
}
@Override
public void glUniformMatrix4(int location, boolean transpose, FloatBuffer value) {
GL20.glUniformMatrix4(location, transpose, value);
GLStateManager.glUniformMatrix4(location, transpose, value);
}
// ===================== THREAD ASSERTIONS =====================
@@ -99,10 +99,14 @@ public class DeferredDrawBatcher {
totalBytes += e.byteLength();
totalVertices += e.vertexCount();
subEnd++;
// Don't try to merge strips, fans, loops or polygons
if (drawMode == GL11.GL_TRIANGLE_STRIP || drawMode == GL11.GL_TRIANGLE_FAN || drawMode == GL11.GL_LINE_STRIP ||
drawMode == GL11.GL_LINE_LOOP || drawMode == GL11.GL_QUAD_STRIP || drawMode == GL11.GL_POLYGON)
break;
}
TessellatorStreamingDrawer.drawPackedBatch(
batchTessellator, ranges, i, subEnd, totalBytes, totalVertices, drawMode, flags);
TessellatorStreamingDrawer.drawPackedBatch(batchTessellator, ranges, i, subEnd, totalBytes, totalVertices, drawMode, flags);
i = subEnd;
}
@@ -224,6 +224,13 @@ public class AngelicaConfig {
})
public static String[] blockCrackFixRenderPassWhitelist__;
@Config.Comment({"List of sprites which should always be treated as translucent.",
"Sprites added to this list will always be considered translucent,",
"",
"Requires texture reload (F3+T) to take effect."})
@Config.DefaultStringList({"jewelrycraft2:blockCrystal"})
public static String[] alwaysTranslucentSprites;
@Config.Comment("Register HardcodedCustomUniforms in Iris Shaders. May help with compatibility in certain shader packs")
@Config.DefaultBoolean(false)
public static boolean enableHardcodedCustomUniforms;
@@ -232,6 +239,31 @@ public class AngelicaConfig {
@Config.DefaultBoolean(true)
public static boolean defineIsIris;
@Config.Comment("ASM transformer exclusion narrowing for mod compatibility. Disable per-mod if narrowing causes class loading issues.")
public static TransformerCompat transformerCompat = new TransformerCompat();
public static class TransformerCompat {
@Config.Comment("Narrow DragonAPI transformer exclusions to allow GL redirection")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public boolean narrowDragonAPI;
@Config.Comment("Narrow Xaeros Minimap/Worldmap transformer exclusions to allow GL redirection")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public boolean narrowXaeros;
@Config.Comment("Narrow AdvancedLightsabers transformer exclusions to allow GL redirection")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public boolean narrowAdvancedLightsabers;
@Config.Comment("Narrow Alfheim transformer exclusions to allow GL redirection")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public boolean narrowAlfheim;
}
@Config.Comment("Renders chunks before neighbors are ready. Improves loading at render distance edges, useful for low render distance servers.")
@Config.DefaultBoolean(false)
public static boolean useVanillaChunkTracking;
@@ -4,6 +4,7 @@ import baubles.common.lib.PlayerHandler;
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
import com.gtnewhorizon.gtnhlib.blockpos.IBlockPos;
import com.gtnewhorizon.gtnhlib.util.CoordinatePacker;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import com.gtnewhorizons.angelica.api.IDynamicLightProducer;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.compat.backhand.BackhandReflectionCompat;
@@ -52,12 +53,18 @@ public class DynamicLights {
private static final double MAX_RADIUS = 7.75;
private static final double MAX_RADIUS_SQUARED = MAX_RADIUS * MAX_RADIUS;
private final Set<IDynamicLightSource> dynamicLightSources = new ObjectOpenHashSet<>();
private IDynamicLightSource[] lightSourceArray = new IDynamicLightSource[0];
private final ReentrantReadWriteLock lightSourcesLock = new ReentrantReadWriteLock();
private volatile int lightSourceCount = 0;
private final ChunkRebuildManager chunkRebuildManager = new ChunkRebuildManager();
private long lastUpdate = System.currentTimeMillis();
private int lastUpdateCount = 0;
/** Must be called under write lock. */
private void rebuildLightSourceArray() {
this.lightSourceArray = this.dynamicLightSources.toArray(new IDynamicLightSource[0]);
}
public static DynamicLights get() {
if (instance == null)
instance = new DynamicLights();
@@ -93,7 +100,7 @@ public class DynamicLights {
if (!isEnabled())
return;
long now = System.currentTimeMillis();
final long now = System.currentTimeMillis();
if (now >= this.lastUpdate + Mode.getDelay()) {
this.lastUpdate = now;
this.lastUpdateCount = 0;
@@ -104,7 +111,7 @@ public class DynamicLights {
int worldTick = 0;
if (AdaptiveTickingEnabled) {
Minecraft mc = Minecraft.getMinecraft();
final Minecraft mc = Minecraft.getMinecraft();
if (mc.theWorld != null && mc.renderViewEntity != null) {
cameraX = mc.renderViewEntity.posX;
cameraY = mc.renderViewEntity.posY + mc.renderViewEntity.getEyeHeight();
@@ -112,15 +119,15 @@ public class DynamicLights {
worldTick = (int) (mc.theWorld.getTotalWorldTime() & 0x7FFFFFFF);
// Calculate look direction from yaw (normalized horizontal direction)
float yaw = mc.renderViewEntity.rotationYaw;
double yawRad = Math.toRadians(yaw);
final float yaw = mc.renderViewEntity.rotationYaw;
final double yawRad = Math.toRadians(yaw);
lookDirX = -Math.sin(yawRad);
lookDirZ = Math.cos(yawRad);
}
}
this.lightSourcesLock.readLock().lock();
for (var lightSource : this.dynamicLightSources) {
for (var lightSource : this.lightSourceArray) {
// Entity type filter
if (!EntityLightConfig.isEntityTypeEnabled(lightSource)) {
continue;
@@ -128,7 +135,7 @@ public class DynamicLights {
// Adaptive ticking filter
if (AdaptiveTickingEnabled) {
AdaptiveTickMode mode = AdaptiveTickCalculator.calculate(
final AdaptiveTickMode mode = AdaptiveTickCalculator.calculate(
lightSource, cameraX, cameraY, cameraZ, lookDirX, lookDirZ);
if (!mode.shouldTickThisFrame(worldTick, lightSource.hashCode())) {
continue;
@@ -150,6 +157,7 @@ public class DynamicLights {
this.lightSourcesLock.writeLock().lock();
if (this.dynamicLightSources.add(lightSource)) {
this.lightSourceCount = this.dynamicLightSources.size();
rebuildLightSourceArray();
}
this.lightSourcesLock.writeLock().unlock();
}
@@ -162,17 +170,11 @@ public class DynamicLights {
public void removeLightSource(@NotNull IDynamicLightSource lightSource) {
this.lightSourcesLock.writeLock().lock();
var dynamicLightSources = this.dynamicLightSources.iterator();
IDynamicLightSource it;
while (dynamicLightSources.hasNext()) {
it = dynamicLightSources.next();
if (it.equals(lightSource)) {
dynamicLightSources.remove();
this.lightSourceCount = this.dynamicLightSources.size();
if (activeRenderer != null)
lightSource.angelica$scheduleTrackedChunksRebuild(activeRenderer);
break;
}
if (this.dynamicLightSources.remove(lightSource)) {
this.lightSourceCount = this.dynamicLightSources.size();
rebuildLightSourceArray();
if (activeRenderer != null)
lightSource.angelica$scheduleTrackedChunksRebuild(activeRenderer);
}
this.lightSourcesLock.writeLock().unlock();
@@ -186,13 +188,14 @@ public class DynamicLights {
public void removeLightSources(@NotNull Predicate<IDynamicLightSource> filter) {
this.lightSourcesLock.writeLock().lock();
var dynamicLightSources = this.dynamicLightSources.iterator();
final var dynamicLightSources = this.dynamicLightSources.iterator();
IDynamicLightSource it;
boolean changed = false;
while (dynamicLightSources.hasNext()) {
it = dynamicLightSources.next();
if (filter.test(it)) {
dynamicLightSources.remove();
this.lightSourceCount = this.dynamicLightSources.size();
changed = true;
if (activeRenderer != null) {
if (it.angelica$getLuminance() > 0)
it.angelica$resetDynamicLight();
@@ -201,6 +204,10 @@ public class DynamicLights {
break;
}
}
if (changed) {
this.lightSourceCount = this.dynamicLightSources.size();
rebuildLightSourceArray();
}
this.lightSourcesLock.writeLock().unlock();
}
@@ -211,7 +218,7 @@ public class DynamicLights {
public void clearLightSources() {
this.lightSourcesLock.writeLock().lock();
var dynamicLightSources = this.dynamicLightSources.iterator();
final var dynamicLightSources = this.dynamicLightSources.iterator();
IDynamicLightSource it;
while (dynamicLightSources.hasNext()) {
it = dynamicLightSources.next();
@@ -223,6 +230,7 @@ public class DynamicLights {
}
}
this.lightSourceCount = 0;
this.lightSourceArray = new IDynamicLightSource[0];
this.lightSourcesLock.writeLock().unlock();
}
@@ -234,7 +242,7 @@ public class DynamicLights {
* @return {@code true} if the light source is tracked, else {@code false}
*/
public boolean containsLightSource(@NotNull IDynamicLightSource lightSource) {
boolean result;
final boolean result;
this.lightSourcesLock.readLock().lock();
result = this.dynamicLightSources.contains(lightSource);
this.lightSourcesLock.readLock().unlock();
@@ -247,7 +255,7 @@ public class DynamicLights {
* @return the number of dynamic light sources emitting light
*/
public int getLightSourcesCount() {
int result;
final int result;
this.lightSourcesLock.readLock().lock();
result = this.dynamicLightSources.size();
@@ -259,7 +267,7 @@ public class DynamicLights {
public double getDynamicLightLevel(int x, int y, int z) {
double result = 0;
this.lightSourcesLock.readLock().lock();
for (var lightSource : this.dynamicLightSources) {
for (var lightSource : this.lightSourceArray) {
result = maxDynamicLightLevel(x, y, z, lightSource, result);
}
this.lightSourcesLock.readLock().unlock();
@@ -273,7 +281,7 @@ public class DynamicLights {
public double getDynamicLightLevel(double x, double y, double z) {
double result = 0;
this.lightSourcesLock.readLock().lock();
for (var lightSource : this.dynamicLightSources) {
for (var lightSource : this.lightSourceArray) {
result = maxDynamicLightLevelExact(x, y, z, lightSource, result);
}
this.lightSourcesLock.readLock().unlock();
@@ -286,19 +294,19 @@ public class DynamicLights {
}
public static double maxDynamicLightLevel(int x, int y, int z, @NotNull IDynamicLightSource lightSource, double currentLightLevel) {
int luminance = lightSource.angelica$getLuminance();
final int luminance = lightSource.angelica$getLuminance();
if (luminance > 0) {
// Can't use Entity#squaredDistanceTo because of eye Y coordinate.
double dx = x - lightSource.angelica$getDynamicLightX() + 0.5;
double dy = y - lightSource.angelica$getDynamicLightY() + 0.5;
double dz = z - lightSource.angelica$getDynamicLightZ() + 0.5;
final double dx = x - lightSource.angelica$getDynamicLightX() + 0.5;
final double dy = y - lightSource.angelica$getDynamicLightY() + 0.5;
final double dz = z - lightSource.angelica$getDynamicLightZ() + 0.5;
double distanceSquared = dx * dx + dy * dy + dz * dz;
final double distanceSquared = dx * dx + dy * dy + dz * dz;
// 7.75 because else we would have to update more chunks and that's not a good idea.
// 15 (max range for blocks) would be too much and a bit cheaty.
if (distanceSquared <= MAX_RADIUS_SQUARED) {
double multiplier = 1.0 - Math.sqrt(distanceSquared) / MAX_RADIUS;
double lightLevel = multiplier * (double) luminance;
final double multiplier = 1.0 - Math.sqrt(distanceSquared) / MAX_RADIUS;
final double lightLevel = multiplier * (double) luminance;
if (lightLevel > currentLightLevel) {
return lightLevel;
}
@@ -312,16 +320,16 @@ public class DynamicLights {
* Used for smooth per-vertex lighting.
*/
public static double maxDynamicLightLevelExact(double x, double y, double z, @NotNull IDynamicLightSource lightSource, double currentLightLevel) {
int luminance = lightSource.angelica$getLuminance();
final int luminance = lightSource.angelica$getLuminance();
if (luminance > 0) {
double dx = x - lightSource.angelica$getDynamicLightX();
double dy = y - lightSource.angelica$getDynamicLightY();
double dz = z - lightSource.angelica$getDynamicLightZ();
final double dx = x - lightSource.angelica$getDynamicLightX();
final double dy = y - lightSource.angelica$getDynamicLightY();
final double dz = z - lightSource.angelica$getDynamicLightZ();
double distanceSquared = dx * dx + dy * dy + dz * dz;
final double distanceSquared = dx * dx + dy * dy + dz * dz;
if (distanceSquared <= MAX_RADIUS_SQUARED) {
double multiplier = 1.0 - Math.sqrt(distanceSquared) / MAX_RADIUS;
double lightLevel = multiplier * (double) luminance;
final double multiplier = 1.0 - Math.sqrt(distanceSquared) / MAX_RADIUS;
final double lightLevel = multiplier * (double) luminance;
if (lightLevel > currentLightLevel) {
return lightLevel;
}
@@ -360,11 +368,11 @@ public class DynamicLights {
this.lightSourcesLock.readLock().lock();
try {
for (IDynamicLightSource source : this.dynamicLightSources) {
double dx = source.angelica$getDynamicLightX() - centerX;
double dy = source.angelica$getDynamicLightY() - centerY;
double dz = source.angelica$getDynamicLightZ() - centerZ;
double distSq = dx * dx + dy * dy + dz * dz;
for (var source : this.lightSourceArray) {
final double dx = source.angelica$getDynamicLightX() - centerX;
final double dy = source.angelica$getDynamicLightY() - centerY;
final double dz = source.angelica$getDynamicLightZ() - centerZ;
final double distSq = dx * dx + dy * dy + dz * dz;
if (distSq <= searchRadiusSq) {
if (result == null) {
@@ -380,6 +388,53 @@ public class DynamicLights {
return result != null ? result : Collections.emptyList();
}
public int getDynamicLightRGB(double x, double y, double z) {
int accum = 0;
this.lightSourcesLock.readLock().lock();
try {
for (var lightSource : this.lightSourceArray) {
accum = accumulateSourceRGB(x, y, z, lightSource, accum);
}
} finally {
this.lightSourcesLock.readLock().unlock();
}
return accum;
}
public int getDynamicLightRGBFromSources(double x, double y, double z, List<IDynamicLightSource> sources) {
if (sources == null || sources.isEmpty()) return 0;
int accum = 0;
for (int i = 0, size = sources.size(); i < size; i++) {
accum = accumulateSourceRGB(x, y, z, sources.get(i), accum);
}
return accum;
}
private static int accumulateSourceRGB(double x, double y, double z, IDynamicLightSource source, int accum) {
final int luminance = source.angelica$getLuminance();
if (luminance <= 0) return accum;
final int rgb = source.angelica$getLuminanceRGB();
if (rgb == 0) return accum;
final double dx = x - source.angelica$getDynamicLightX();
final double dy = y - source.angelica$getDynamicLightY();
final double dz = z - source.angelica$getDynamicLightZ();
final double distSq = dx * dx + dy * dy + dz * dz;
if (distSq > MAX_RADIUS_SQUARED) return accum;
final double multiplier = 1.0 - Math.sqrt(distSq) / MAX_RADIUS;
final int r = (int) (BlockLightProvider.unpackR(rgb) * multiplier);
final int g = (int) (BlockLightProvider.unpackG(rgb) * multiplier);
final int b = (int) (BlockLightProvider.unpackB(rgb) * multiplier);
return BlockLightProvider.packRGB(
Math.max(BlockLightProvider.unpackR(accum), r),
Math.max(BlockLightProvider.unpackG(accum), g),
Math.max(BlockLightProvider.unpackB(accum), b));
}
public double getDynamicLightLevelFromSources(double x, double y, double z, List<IDynamicLightSource> sources) {
if (sources == null || sources.isEmpty()) {
return 0;
@@ -403,10 +458,10 @@ public class DynamicLights {
// lightmap is (skyLevel << 20 | blockLevel << 4)
// Get vanilla block light level.
int blockLevel = (lightmap & 0xFFFF) >> 4;
final int blockLevel = (lightmap & 0xFFFF) >> 4;
if (dynamicLightLevel > blockLevel) {
// Equivalent to a << 4 bitshift with a little quirk: this one ensure more precision (more decimals are saved).
int luminance = (int) (dynamicLightLevel * 16.0);
final int luminance = (int) (dynamicLightLevel * 16.0);
lightmap &= 0xfff00000;
lightmap |= luminance & 0x000fffff;
}
@@ -485,8 +540,8 @@ public class DynamicLights {
* @param lightSource the light source
*/
public static void updateTracking(@NotNull IDynamicLightSource lightSource) {
boolean enabled = lightSource.angelica$isDynamicLightEnabled();
int luminance = lightSource.angelica$getLuminance();
final boolean enabled = lightSource.angelica$isDynamicLightEnabled();
final int luminance = lightSource.angelica$getLuminance();
if (!enabled && luminance > 0) {
lightSource.angelica$setDynamicLightEnabled(true);
@@ -503,9 +558,9 @@ public class DynamicLights {
* @return the luminance of the item
*/
public static int getLuminanceFromItemStack(@NotNull ItemStack stack) {
Item item = stack.getItem();
final Item item = stack.getItem();
if (item instanceof ItemBlock itemBlock) {
Block block = itemBlock.field_150939_a;
final Block block = itemBlock.field_150939_a;
if (block != null) {
return block.getLightValue();
}
@@ -522,7 +577,7 @@ public class DynamicLights {
if (entity.isBurning()) return 15;
boolean inWater = entity.isInsideOfMaterial(Material.water);
final boolean inWater = entity.isInsideOfMaterial(Material.water);
// TODO only have certain items not glow in water?
if (inWater) return 0;
@@ -547,23 +602,23 @@ public class DynamicLights {
player instanceof IBattlePlayer battlePlayer &&
battlePlayer.battlegear2$isBattlemode()
) {
ItemStack offhand = Battlegear2Compat.getBattlegear2Offhand(player);
final ItemStack offhand = Battlegear2Compat.getBattlegear2Offhand(player);
if (offhand != null) {
luminance = Math.max(luminance, getLuminanceFromItemStack(offhand));
}
}
else if (ModStatus.isBackhandLoaded){
ItemStack offhand = BackhandReflectionCompat.getOffhandItem(player);
final ItemStack offhand = BackhandReflectionCompat.getOffhandItem(player);
if (offhand != null) {
luminance = Math.max(luminance, getLuminanceFromItemStack(offhand));
}
}
if (ModStatus.isBaublesLoaded){
var playerBaubles = PlayerHandler.getPlayerBaubles(player);
final var playerBaubles = PlayerHandler.getPlayerBaubles(player);
if (playerBaubles != null){
for (int i = 0; i < playerBaubles.getSizeInventory(); i++){
var stack = playerBaubles.getStackInSlot(i);
final var stack = playerBaubles.getStackInSlot(i);
if (stack != null){
luminance = Math.max(luminance, getLuminanceFromItemStack(stack));
}
@@ -1,5 +1,6 @@
package com.gtnewhorizons.angelica.dynamiclights;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -78,4 +79,13 @@ public interface IDynamicLightSource {
boolean angelica$updateDynamicLight(@NotNull IDynamicLightWorldRenderer renderer);
void angelica$scheduleTrackedChunksRebuild(@NotNull IDynamicLightWorldRenderer renderer);
/**
* Returns the RGB luminance of the light source. Each channel 0-15, packed as {@code (r << 8) | (g << 4) | b}.
* Default implementation returns white light at the scalar luminance level.
*/
default int angelica$getLuminanceRGB() {
final int l = angelica$getLuminance();
return BlockLightProvider.packRGB(l, l, l);
}
}
@@ -25,6 +25,7 @@ import net.minecraft.client.renderer.EntityRenderer;
import net.minecraftforge.client.GuiIngameForge;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import thaumcraft.common.Thaumcraft;
import xaero.common.core.XaeroMinimapCore;
@@ -69,6 +70,12 @@ public class HUDCaching {
XaeroMinimapCore.beforeIngameGuiRender(partialTicks);
}
GLStateManager.disableLighting();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.disableTexture();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.enableTexture();
if (!AngelicaConfig.hudCachingActive || !GLStateManager.isFramebufferEnabled()) {
ingame.renderGameOverlay(partialTicks, hasScreen, mouseX, mouseY);
return;
@@ -14,6 +14,7 @@ import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.texture.pbr.PBRTextureManager;
import net.coderbot.iris.vertices.ImmediateState;
public class IrisGLSMBridge {
@@ -114,10 +115,10 @@ public class IrisGLSMBridge {
if (!drp.shouldOverrideShaders()) return;
if (drp.getActivePassProgramId() == -1) return;
if (DepthColorStorage.isOwnedProgram(event.newProgram)) {
if (!ImmediateState.isRenderingLevel || DepthColorStorage.isOwnedProgram(event.newProgram)) {
DepthColorStorage.unlockDepthColor();
} else {
DepthColorStorage.disableDepthColor();
drp.onModProgramOverride();
}
});
}
@@ -135,12 +135,23 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
return null;
}
/** Publish a transformer-narrowing toggle to the blackboard; read by AngelicaLateTweaker.narrowEnabled(). */
private static void narrowTransformerConfig(String mod, boolean enabled) {
Launch.blackboard.put("angelica.narrow." + mod, enabled);
}
@Override
public void injectData(Map<String, Object> data) {
OBF_ENV = (Boolean) data.get("runtimeDeobfuscationEnabled");
// Directly add this to the MixinServiceLaunchWrapper tweaker's list of Tweak Classes
final List<String> tweaks = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES);
if (tweaks != null) {
// Bridge transformer compat config to blackboard for AngelicaLateTweaker
narrowTransformerConfig("DragonAPI", AngelicaConfig.transformerCompat.narrowDragonAPI);
narrowTransformerConfig("Xaeros", AngelicaConfig.transformerCompat.narrowXaeros);
narrowTransformerConfig("AdvancedLightsabers", AngelicaConfig.transformerCompat.narrowAdvancedLightsabers);
narrowTransformerConfig("Alfheim", AngelicaConfig.transformerCompat.narrowAlfheim);
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.IncompatibleModsDisablerTweaker");
if (AngelicaConfig.enableHudCaching) {
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.XaerosTransformerDisablerTweaker");
@@ -37,10 +37,8 @@ public class AngelicaLateTweaker implements ITweaker {
exceptionsField.setAccessible(true);
final Set<String> exceptions = (Set<String>) exceptionsField.get(classLoader);
if (exceptions.remove("Reika.DragonAPI.ASM")) {
// Don't read ASMCallsClient and Patchers/Fixes/WorldRenderAlpha. The rest are fair game.
// Re-add the other non utility classes
if (narrowEnabled("DragonAPI") && exceptions.remove("Reika.DragonAPI.ASM")) {
// Re-add non-GL classes; ASMCallsClient and utility classes with GL calls are left exposed
exceptions.add("Reika.DragonAPI.ASM.Patchers");
exceptions.add("Reika.DragonAPI.ASM.Profiling");
exceptions.add("Reika.DragonAPI.ASM.APIStripper");
@@ -52,22 +50,60 @@ public class AngelicaLateTweaker implements ITweaker {
exceptions.add("Reika.DragonAPI.ASM.InterfaceInjector");
exceptions.add("Reika.DragonAPI.ASM.SpecialBiomePlacement");
exceptions.add("Reika.DragonAPI.ASM.StructureLootHooks");
FMLRelaunchLog.info("[Angelica] Narrowed Reika.DragonAPI.ASM transformer exclusion to allow GL redirection of utility classes");
FMLRelaunchLog.info("[Angelica] Narrowed Reika.DragonAPI.ASM transformer exclusion to allow GL redirection");
}
if (exceptions.remove("xaero.common.core")) {
exceptions.add("xaero.common.core.transformer");
FMLRelaunchLog.info("[Angelica] Narrowed xaero.common.core transformer exclusion to allow GL redirection");
if (narrowEnabled("Xaeros")) {
if (exceptions.remove("xaero.common.core")) {
exceptions.add("xaero.common.core.transformer");
FMLRelaunchLog.info("[Angelica] Narrowed xaero.common.core transformer exclusion to allow GL redirection");
}
if (exceptions.remove("xaero.map.core")) {
exceptions.add("xaero.map.core.transformer");
FMLRelaunchLog.info("[Angelica] Narrowed xaero.map.core transformer exclusion to allow GL redirection");
}
}
if (exceptions.remove("xaero.map.core")) {
exceptions.add("xaero.map.core.transformer");
FMLRelaunchLog.info("[Angelica] Narrowed xaero.map.core transformer exclusion to allow GL redirection");
if (narrowEnabled("AdvancedLightsabers") && exceptions.remove("com.fiskmods.lightsabers.asm")) {
exceptions.add("com.fiskmods.lightsabers.asm.ALLoadingPlugin");
exceptions.add("com.fiskmods.lightsabers.asm.ASMHooks");
exceptions.add("com.fiskmods.lightsabers.asm.transformers");
FMLRelaunchLog.info("[Angelica] Narrowed com.fiskmods.lightsabers.asm 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");
exceptions.add("alfheim.common.core.asm.hook.Botania18AndUpBackport");
exceptions.add("alfheim.common.core.asm.hook.ElementalDamageAdapter");
exceptions.add("alfheim.common.core.asm.hook.integration");
exceptions.add("alfheim.common.core.asm.hook.extender.FurnaceExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.ItemAuraRingExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.ItemLensExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.ItemTwigWandExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.LightRelayExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.PureDaisyExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.QuartzExtender");
exceptions.add("alfheim.common.core.asm.hook.extender.RelicHooks");
exceptions.add("alfheim.common.core.asm.hook.extender.SparkExtender");
exceptions.add("alfheim.common.core.asm.hook.fixes.BotaniaGlowingRenderFixes");
exceptions.add("alfheim.common.core.asm.hook.fixes.CorporeaInputFix");
exceptions.add("alfheim.common.core.asm.hook.fixes.GodAttributesHooks");
exceptions.add("alfheim.common.core.asm.hook.fixes.RecipeAncientWillsFix");
FMLRelaunchLog.info("[Angelica] Narrowed alfheim.common.core.asm.hook transformer exclusion to allow GL redirection");
}
} catch (Exception e) {
FMLRelaunchLog.warning("[Angelica] Failed to narrow transformer exclusions: %s", e.getMessage());
}
}
private static boolean narrowEnabled(String mod) {
return !Boolean.FALSE.equals(Launch.blackboard.get("angelica.narrow." + mod));
}
@Override
public String getLaunchTarget() {
return null;
@@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.mixins;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.config.CompatConfig;
import jss.notfine.config.MCPatcherForgeConfig;
@@ -35,6 +36,7 @@ public enum Mixins implements IMixins {
, "angelica.MixinMinecraft"
, "angelica.MixinMinecraft_FrameHook"
, "angelica.MixinMinecraftServer"
, "angelica.bugfixes.MixinItemRenderer_EdgeDepth"
, "angelica.bugfixes.MixinRenderGlobal_DestroyBlock"
, "angelica.bugfixes.MixinRendererLivingEntity_EyeDepth"
, "angelica.debug.MixinMinecraft_FPSCap"
@@ -214,6 +216,22 @@ public enum Mixins implements IMixins {
)
),
CELERITAS_COLORED_LIGHT(new MixinBuilder("Colored light infrastructure for celeritas light pipeline")
.setPhase(Phase.EARLY)
.setApplyIf(() -> {
BlockLightProvider.freezeMixinConfig();
return AngelicaConfig.enableCeleritas && BlockLightProvider.coloredLightEnabled();
})
.addClientMixins(
"celeritas.light.MixinQuadLightData",
"celeritas.light.MixinLightDataAccess",
"celeritas.light.MixinLightDataCache",
"celeritas.light.MixinAoFaceData",
"celeritas.light.MixinSmoothLightPipeline",
"celeritas.light.MixinFlatLightPipeline"
)
),
IRIS_SHADERS(new MixinBuilder()
.setPhase(Phase.EARLY)
.setApplyIf(() -> AngelicaConfig.enableIris)
@@ -698,7 +716,7 @@ public enum Mixins implements IMixins {
private final MixinBuilder builder;
private static String[] addPrefix(String prefix, String... values) {
List<String> list = new ArrayList<>(values.length);
final List<String> list = new ArrayList<>(values.length);
for (String s : values) {
list.add(prefix + s);
}
@@ -14,7 +14,6 @@ import com.gtnewhorizons.angelica.debug.TPSGraph;
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.client.debug.OpenGLDebugging;
import com.gtnewhorizons.angelica.hudcaching.HUDCaching;
import com.gtnewhorizons.angelica.iris.IrisGLSMBridge;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
@@ -27,7 +26,6 @@ import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskRegistr
import com.gtnewhorizons.angelica.rendering.celeritas.threading.DefaultChunkTaskProvider;
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ThreadedChunkTaskProvider;
import com.gtnewhorizons.angelica.zoom.Zoom;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
@@ -46,12 +44,13 @@ import net.coderbot.iris.Iris;
import net.coderbot.iris.client.IrisDebugScreenHandler;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiVideoSettings;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.Direction;
import net.minecraft.util.MathHelper;
@@ -111,8 +110,6 @@ public class ClientProxy extends CommonProxy {
}
}
private static KeyBinding glsmKeyBinding;
@Override
public void init(FMLInitializationEvent event) {
super.init(event);
@@ -141,8 +138,6 @@ public class ClientProxy extends CommonProxy {
FMLCommonHandler.instance().bus().register(this);
MinecraftForge.EVENT_BUS.register(this);
glsmKeyBinding = new KeyBinding("Print GLSM Debug", Keyboard.KEY_NONE, "Angelica");
ClientRegistry.registerKeyBinding(glsmKeyBinding);
if (ModStatus.isBetterCrashesLoaded) {
BetterCrashesCompat.init();
@@ -160,16 +155,6 @@ public class ClientProxy extends CommonProxy {
}
}
private boolean wasGLSMKeyPressed;
@SubscribeEvent
public void onKeypress(TickEvent.ClientTickEvent event) {
final boolean isPressed = glsmKeyBinding.getKeyCode() != 0 && GameSettings.isKeyDown(glsmKeyBinding);
if (isPressed && !wasGLSMKeyPressed) {
OpenGLDebugging.checkGLSM();
}
wasGLSMKeyPressed = isPressed;
}
@Override
public void postInit(FMLPostInitializationEvent event) {
@@ -177,7 +162,7 @@ public class ClientProxy extends CommonProxy {
if (ModStatus.isLotrLoaded && AngelicaConfig.enableCeleritas && CompatConfig.fixLotr) {
try {
Class<?> lotrRendering = Class.forName("lotr.common.coremod.LOTRReplacedMethods$BlockRendering");
final Class<?> lotrRendering = Class.forName("lotr.common.coremod.LOTRReplacedMethods$BlockRendering");
ReflectionHelper.setPrivateValue(lotrRendering, null, new ConcurrentHashMap<>(), "naturalBlockClassTable");
ReflectionHelper.setPrivateValue(lotrRendering, null, new ConcurrentHashMap<>(), "naturalBlockTable");
ReflectionHelper.setPrivateValue(lotrRendering, null, new ConcurrentHashMap<>(), "cachedNaturalBlocks");
@@ -192,9 +177,9 @@ public class ClientProxy extends CommonProxy {
@SubscribeEvent
public void onTick(TickEvent.ServerTickEvent event) {
if (FMLCommonHandler.instance().getSide().isClient() && event.phase == TickEvent.Phase.END) {
IntegratedServer srv = Minecraft.getMinecraft().getIntegratedServer();
final IntegratedServer srv = Minecraft.getMinecraft().getIntegratedServer();
if (srv != null) {
long currentTickTime = srv.tickTimeArray[srv.getTickCounter() % 100];
final long currentTickTime = srv.tickTimeArray[srv.getTickCounter() % 100];
lastIntegratedTickTime = lastIntegratedTickTime * 0.8F + (float) currentTickTime / 1000000.0F * 0.2F;
} else lastIntegratedTickTime = 0;
}
@@ -211,30 +196,30 @@ public class ClientProxy extends CommonProxy {
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onRenderOverlay(RenderGameOverlayEvent.Text event) {
Minecraft mc = Minecraft.getMinecraft();
if (!mc.gameSettings.showDebugInfo || event.left.isEmpty()) return;
final Minecraft mc = Minecraft.getMinecraft();
if (event.isCanceled() || !mc.gameSettings.showDebugInfo || event.left.isEmpty()) return;
NetHandlerPlayClient cl = mc.getNetHandler();
final NetHandlerPlayClient cl = mc.getNetHandler();
if (cl != null) {
IntegratedServer srv = mc.getIntegratedServer();
final IntegratedServer srv = mc.getIntegratedServer();
if (srv != null) {
String s = String.format("Integrated server @ %.0f ms ticks", lastIntegratedTickTime);
final String s = String.format("Integrated server @ %.0f ms ticks", lastIntegratedTickTime);
event.left.add(Math.min(event.left.size(), 1), s);
}
}
if (AngelicaConfig.showBlockDebugInfo && mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
if (!event.right.isEmpty() && !Objects.firstNonNull(event.right.get(event.right.size() - 1), "").isEmpty()) event.right.add("");
Block block = mc.theWorld.getBlock(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ);
int meta = mc.theWorld.getBlockMetadata(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ);
final Block block = mc.theWorld.getBlock(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ);
final int meta = mc.theWorld.getBlockMetadata(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ);
event.right.add(Block.blockRegistry.getNameForObject(block));
event.right.add("meta: " + meta);
}
if (DynamicLights.isEnabled()) {
var builder = new StringBuilder("Dynamic Light Sources: ");
DynamicLights dl = DynamicLights.get();
final var builder = new StringBuilder("Dynamic Light Sources: ");
final DynamicLights dl = DynamicLights.get();
builder.append(dl.getLightSourcesCount()).append(" (U: ").append(dl.getLastUpdateCount()).append(')');
event.right.add(builder.toString());
@@ -248,8 +233,8 @@ public class ClientProxy extends CommonProxy {
.startsWith("y:") && Objects.firstNonNull(event.left.get(i + 2), "").startsWith("z:") && Objects.firstNonNull(event.left.get(i + 3), "")
.startsWith("f:")) {
hasReplacedXYZ = true;
int heading = MathHelper.floor_double((double) (mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
String heading_str = switch (heading) {
final int heading = MathHelper.floor_double((double) (mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
final String heading_str = switch (heading) {
case 0 -> "Towards positive Z";
case 1 -> "Towards negative X";
case 2 -> "Towards negative Z";
@@ -257,9 +242,9 @@ public class ClientProxy extends CommonProxy {
default -> throw new RuntimeException();
};
event.left.set(i, String.format("XYZ: %.3f / %.5f / %.3f", mc.thePlayer.posX, mc.thePlayer.boundingBox.minY, mc.thePlayer.posZ));
int bX = MathHelper.floor_double(mc.thePlayer.posX);
int bY = MathHelper.floor_double(mc.thePlayer.boundingBox.minY);
int bZ = MathHelper.floor_double(mc.thePlayer.posZ);
final int bX = MathHelper.floor_double(mc.thePlayer.posX);
final int bY = MathHelper.floor_double(mc.thePlayer.boundingBox.minY);
final int bZ = MathHelper.floor_double(mc.thePlayer.posZ);
event.left.set(i + 1, String.format("Block: %d %d %d [%d %d %d]", bX, bY, bZ, bX & 15, bY & 15, bZ & 15));
event.left.set(i + 2, String.format("Chunk: %d %d %d", bX >> 4, bY >> 4, bZ >> 4));
event.left.set(
@@ -270,15 +255,14 @@ public class ClientProxy extends CommonProxy {
MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationYaw),
MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationPitch)));
Chunk chunk = this.mc.theWorld.getChunkFromBlockCoords(bX, bZ);
event.left.set(
i + 4, String.format(
"lc: %d b: %s bl: %d sl: %d rl: %d",
chunk.getTopFilledSegment() + 15,
chunk.getBiomeGenForWorldCoords(bX & 15, bZ & 15, mc.theWorld.getWorldChunkManager()).biomeName,
chunk.getSavedLightValue(EnumSkyBlock.Block, bX & 15, MathHelper.clamp_int(bY, 0, 255), bZ & 15),
chunk.getSavedLightValue(EnumSkyBlock.Sky, bX & 15, MathHelper.clamp_int(bY, 0, 255), bZ & 15),
chunk.getBlockLightValue(bX & 15, MathHelper.clamp_int(bY, 0, 255), bZ & 15, 0)));
final Chunk chunk = this.mc.theWorld.getChunkFromBlockCoords(bX, bZ);
event.left.set(i + 4, String.format(
"lc: %d b: %s bl: %d sl: %d rl: %d",
chunk.getTopFilledSegment() + 15,
chunk.getBiomeGenForWorldCoords(bX & 15, bZ & 15, mc.theWorld.getWorldChunkManager()).biomeName,
chunk.getSavedLightValue(EnumSkyBlock.Block, bX & 15, MathHelper.clamp_int(bY, 0, 255), bZ & 15),
chunk.getSavedLightValue(EnumSkyBlock.Sky, bX & 15, MathHelper.clamp_int(bY, 0, 255), bZ & 15),
chunk.getBlockLightValue(bX & 15, MathHelper.clamp_int(bY, 0, 255), bZ & 15, 0)));
}
}
// Draw a frametime graph
@@ -1,6 +1,9 @@
package com.gtnewhorizons.angelica.rendering.celeritas;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.api.ExtQuadLightData;
import com.gtnewhorizons.angelica.api.TintComputer;
import com.gtnewhorizons.angelica.api.TintRegistry;
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
import com.gtnewhorizons.angelica.dynamiclights.IDynamicLightSource;
import com.gtnewhorizons.angelica.rendering.StateAwareTessellator;
@@ -17,8 +20,8 @@ import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import org.embeddedt.embeddium.api.util.ColorABGR;
import org.embeddedt.embeddium.impl.model.light.LightPipeline;
import org.embeddedt.embeddium.impl.model.light.data.LightDataAccess;
import org.embeddedt.embeddium.impl.model.light.data.QuadLightData;
import org.embeddedt.embeddium.impl.model.light.flat.FlatLightPipeline;
import org.embeddedt.embeddium.impl.model.light.smooth.SmoothLightPipeline;
@@ -33,7 +36,6 @@ import org.embeddedt.embeddium.impl.render.chunk.terrain.material.Material;
import org.embeddedt.embeddium.impl.render.chunk.vertex.format.ChunkVertexEncoder;
import org.embeddedt.embeddium.impl.util.QuadUtil;
import java.util.Arrays;
import java.util.List;
public class AngelicaChunkBuildContext extends ChunkBuildContext {
@@ -56,7 +58,8 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
private final VertexArrayQuadView quadView;
private boolean lightPipelineReady = false;
private int originX, originY, originZ;
private IBlockAccess blockAccess;
private float cachedSkylightSubtracted;
private final boolean hasColoredLight;
public AngelicaChunkBuildContext(RenderPassConfiguration<?> renderPassConfiguration, WorldClient world) {
super(renderPassConfiguration);
@@ -65,6 +68,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
this.smoothLightPipeline = new SmoothLightPipeline(lightDataCache, VanillaDiffuseProvider.INSTANCE, false);
this.flatLightPipeline = new FlatLightPipeline(lightDataCache, VanillaDiffuseProvider.INSTANCE, false);
this.quadView = new VertexArrayQuadView(vertices);
this.hasColoredLight = quadLightData instanceof ExtQuadLightData;
}
public void setupLightPipeline(int minBlockX, int minBlockY, int minBlockZ) {
@@ -72,7 +76,6 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
}
public void setupLightPipeline(IBlockAccess blockAccess, int minBlockX, int minBlockY, int minBlockZ) {
this.blockAccess = blockAccess;
this.originX = minBlockX;
this.originY = minBlockY;
this.originZ = minBlockZ;
@@ -81,6 +84,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
smoothLightPipeline.reset();
flatLightPipeline.reset();
lightPipelineReady = true;
cachedSkylightSubtracted = Minecraft.getMinecraft().theWorld.skylightSubtracted;
}
public void setupDynamicLights(int chunkOriginX, int chunkOriginY, int chunkOriginZ) {
@@ -219,10 +223,13 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
}
}
// Apply RGB block light tint from provider
applyBlockLightTint(worldX, worldY, worldZ, vertices);
final int faceBit = 1 << facing.ordinal();
final Material correctMaterial;
if ((facesAtBaseMaterial & faceBit) != 0) {
// Face already has a non-demoted quad — skip selectMaterial entirely
// Face already has a non-demoted quad, skip selectMaterial entirely
correctMaterial = material;
} else {
correctMaterial = selectMaterial(material, sprite, isShaderPackOverride);
@@ -239,4 +246,50 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
builder.getVertexBuffer(facing).push(vertices, correctMaterial);
}
}
private final float[] tintResult = new float[3];
private void applyBlockLightTint(int x, int y, int z, ChunkVertexEncoder.Vertex[] vertices) {
if (!hasColoredLight) return;
final ExtQuadLightData ext = (ExtQuadLightData) quadLightData;
final boolean hasBlock = ext.angelica$isRGBValid();
final boolean hasSky = ext.angelica$isSkyRGBValid();
if (!hasBlock && !hasSky) return;
if (hasBlock) ext.angelica$setRGBValid(false);
if (hasSky) ext.angelica$setSkyRGBValid(false);
final float[] blockR = hasBlock ? ext.angelica$getR() : null;
final float[] blockG = hasBlock ? ext.angelica$getG() : null;
final float[] blockB = hasBlock ? ext.angelica$getB() : null;
final float[] skyR = hasSky ? ext.angelica$getSkyR() : null;
final float[] skyG = hasSky ? ext.angelica$getSkyG() : null;
final float[] skyB = hasSky ? ext.angelica$getSkyB() : null;
final float sub = cachedSkylightSubtracted;
final TintComputer tintComputer = TintRegistry.getCurrent();
for (int i = 0; i < 4; i++) {
final float br = hasBlock ? blockR[i] : 0;
final float bg = hasBlock ? blockG[i] : 0;
final float bb = hasBlock ? blockB[i] : 0;
final float sr = hasSky ? Math.max(0, skyR[i] - sub) : 0;
final float sg = hasSky ? Math.max(0, skyG[i] - sub) : 0;
final float sb = hasSky ? Math.max(0, skyB[i] - sub) : 0;
// Fast-path: full white sky with no block light, no tint needed
if (br == 0 && bg == 0 && bb == 0 && sr >= 15f && sg >= 15f && sb >= 15f) continue;
tintComputer.computeTint(br, bg, bb, sr, sg, sb, tintResult);
final float rTint = tintResult[0];
final float gTint = tintResult[1];
final float bTint = tintResult[2];
if (rTint >= 1.0f && gTint >= 1.0f && bTint >= 1.0f) continue;
final int color = vertices[i].color;
final int vr = Math.min(255, (int) (ColorABGR.unpackRed(color) * rTint));
final int vg = Math.min(255, (int) (ColorABGR.unpackGreen(color) * gTint));
final int vb = Math.min(255, (int) (ColorABGR.unpackBlue(color) * bTint));
vertices[i].color = ColorABGR.pack(vr, vg, vb, ColorABGR.unpackAlpha(color));
}
}
}
@@ -0,0 +1,85 @@
package com.gtnewhorizons.angelica.rendering.celeritas.compat;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
/**
* Inlined data from package-private {@code AoNeighborInfo} -- edge face directions,
* bilinear corner weight formulas, and depth formulas per face direction.
*/
public final class AoHelper {
private static final ModelQuadFacing[][] FACES = {
{ ModelQuadFacing.NEG_Y, ModelQuadFacing.POS_Y, ModelQuadFacing.NEG_Z, ModelQuadFacing.POS_Z }, // POS_X
{ ModelQuadFacing.POS_X, ModelQuadFacing.NEG_X, ModelQuadFacing.NEG_Z, ModelQuadFacing.POS_Z }, // POS_Y
{ ModelQuadFacing.NEG_X, ModelQuadFacing.POS_X, ModelQuadFacing.NEG_Y, ModelQuadFacing.POS_Y }, // POS_Z
{ ModelQuadFacing.POS_Y, ModelQuadFacing.NEG_Y, ModelQuadFacing.NEG_Z, ModelQuadFacing.POS_Z }, // NEG_X
{ ModelQuadFacing.NEG_X, ModelQuadFacing.POS_X, ModelQuadFacing.NEG_Z, ModelQuadFacing.POS_Z }, // NEG_Y
{ ModelQuadFacing.POS_Y, ModelQuadFacing.NEG_Y, ModelQuadFacing.POS_X, ModelQuadFacing.NEG_X }, // NEG_Z
};
/**
* Corner remap table derived from each AoNeighborInfo.mapCorners.
* remap[outIdx] = inIdx.
*/
public static final int[][] CORNER_REMAP = {
{ 3, 0, 1, 2 }, // POS_X
{ 2, 3, 0, 1 }, // POS_Y
{ 0, 1, 2, 3 }, // POS_Z
{ 1, 2, 3, 0 }, // NEG_X
{ 0, 1, 2, 3 }, // NEG_Y
{ 1, 2, 3, 0 }, // NEG_Z
};
private AoHelper() {}
public static ModelQuadFacing[] getFaces(ModelQuadFacing direction) {
return FACES[direction.ordinal()];
}
public static void calculateCornerWeights(ModelQuadFacing direction, float x, float y, float z, float[] out) {
final float u, v;
switch (direction) {
case POS_X -> {
u = z;
v = 1.0f - y;
}
case POS_Y -> {
u = z;
v = x;
}
case POS_Z -> {
u = y;
v = 1.0f - x;
}
case NEG_X -> {
u = z;
v = y;
}
case NEG_Y -> {
u = z;
v = 1.0f - x;
}
case NEG_Z -> {
u = 1.0f - x;
v = y;
}
default -> throw new IllegalArgumentException();
}
out[0] = v * u;
out[1] = v * (1.0f - u);
out[2] = (1.0f - v) * (1.0f - u);
out[3] = (1.0f - v) * u;
}
public static float getDepth(ModelQuadFacing direction, float x, float y, float z) {
return switch (direction) {
case POS_X -> 1.0f - x;
case POS_Y -> 1.0f - y;
case POS_Z -> 1.0f - z;
case NEG_X -> x;
case NEG_Y -> y;
case NEG_Z -> z;
default -> throw new IllegalArgumentException();
};
}
}
@@ -1,5 +1,6 @@
package com.gtnewhorizons.angelica.rendering.celeritas.world;
import com.gtnewhorizons.angelica.api.SectionLightData;
import com.gtnewhorizons.angelica.api.IBlockAccessExtended;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos;
@@ -84,11 +85,14 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
// Local Section->Light table
private final NibbleArray[][] lightArrays;
// Per-section RGB light data (captured from BlockLightProvider on main thread)
private final SectionLightData[] sectionLightData;
// Local section copies
private ClonedChunkSection[] sections;
// Biome data for each chunk section
private BiomeGenBase[][] biomeData;
private final BiomeGenBase[][] biomeData;
// The starting point from which this slice captures blocks
private int baseX, baseY, baseZ;
@@ -158,6 +162,7 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
this.metadataArrays = new int[SECTION_TABLE_ARRAY_SIZE][];
this.biomeData = new BiomeGenBase[SECTION_TABLE_ARRAY_SIZE][];
this.lightArrays = new NibbleArray[SECTION_TABLE_ARRAY_SIZE][LIGHT_TYPES.length];
this.sectionLightData = new SectionLightData[SECTION_TABLE_ARRAY_SIZE];
if (ModStatus.isFluidLoggedLoaded) {
this.fluidArrays = new Fluid[SECTION_TABLE_ARRAY_SIZE][];
@@ -220,6 +225,7 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
this.lightArrays[idx][EnumSkyBlock.Block.ordinal()] = section.getLightArray(EnumSkyBlock.Block);
this.lightArrays[idx][EnumSkyBlock.Sky.ordinal()] = section.getLightArray(EnumSkyBlock.Sky);
this.sectionLightData[idx] = section.getSectionLightData();
}
}
}
@@ -380,6 +386,24 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
return lightArray.get(relX & 15, relY & 15, relZ & 15);
}
public SectionLightData getSectionLightData(int x, int y, int z) {
if (!blockBoxContains(this.volume, x, y, z)) {
return null;
}
final int relX = x - this.baseX;
final int relY = y - this.baseY;
final int relZ = z - this.baseZ;
return this.sectionLightData[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)];
}
public List<IDynamicLightSource> getChunkLightSources() {
return chunkLightSources;
}
public DynamicLights getDynamicLightsInstance() {
return dynamicLightsInstance;
}
@Override
public World getWorld() {
return this.world;
@@ -1,6 +1,8 @@
package com.gtnewhorizons.angelica.rendering.celeritas.world.cloned;
import com.falsepattern.endlessids.mixin.helpers.ChunkBiomeHook;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import com.gtnewhorizons.angelica.api.SectionLightData;
import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos;
@@ -33,6 +35,7 @@ public class ClonedChunkSection {
private ChunkSectionPos pos;
private ExtendedBlockStorageExt data;
private BiomeGenBase[] biomeData;
private SectionLightData sectionLightData;
private final Short2ObjectOpenHashMap<TileEntity> tileEntities;
private long lastUsedTimestamp = Long.MAX_VALUE;
@@ -75,6 +78,8 @@ public class ClonedChunkSection {
this.biomeData[(x & 15) | ((z & 15) << 4)] = world.getBiomeGenForCoords(x, z);
}
}
this.sectionLightData = BlockLightProvider.getInstance().prepareSectionData(chunk, pos.y);
}
@SuppressWarnings("unchecked")
@@ -127,6 +132,10 @@ public class ClonedChunkSection {
return data.getBlocklightArray();
}
public SectionLightData getSectionLightData() {
return this.sectionLightData;
}
public BiomeGenBase[] getBiomeData() {
return this.biomeData;
}
@@ -56,16 +56,19 @@ final class Enchantment extends OverrideBase {
GLStateManager.glEnable(GL11.GL_ALPHA_TEST);
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.01f);
GLStateManager.glEnable(GL11.GL_BLEND);
GLStateManager.glDepthFunc(GL11.GL_EQUAL);
lightingWasEnabled = GLStateManager.glGetBoolean(GL11.GL_LIGHTING);
GLStateManager.glDisable(GL11.GL_LIGHTING);
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
}
static void endOuter3D() {
GLStateManager.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
GLStateManager.glDisable(GL11.GL_BLEND);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glDepthMask(true);
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
if (lightingWasEnabled) {
GLStateManager.glEnable(GL11.GL_LIGHTING);
}
@@ -139,6 +142,17 @@ final class Enchantment extends OverrideBase {
return;
}
begin(intensity);
// Depth pre-pass
GLStateManager.glColorMask(false, false, false, false);
GLStateManager.glDepthMask(true);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
ItemRenderer.renderItemIn2D(Tessellator.instance, 1.0f, 0.0f, 0.0f, 1.0f, width, height, ITEM_2D_THICKNESS);
// Color pass
GLStateManager.glColorMask(true, true, true, true);
GLStateManager.glDepthMask(false);
GLStateManager.glDepthFunc(GL11.GL_EQUAL);
ItemRenderer.renderItemIn2D(Tessellator.instance, 1.0f, 0.0f, 0.0f, 1.0f, width, height, ITEM_2D_THICKNESS);
end();
}
@@ -26,7 +26,6 @@ import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.util.glu.GLU;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
@@ -47,8 +46,8 @@ public class FancyDial {
private static final double ANGLE_UNSET = Double.MAX_VALUE;
private static final int NUM_SCRATCH_TEXTURES = 3;
private static final boolean fboSupported = GLContext.getCapabilities().GL_EXT_framebuffer_object;
private static final boolean gl13Supported = GLContext.getCapabilities().OpenGL13;
private static final boolean fboSupported = GLStateManager.capabilities.GL_EXT_framebuffer_object;
private static final boolean gl13Supported = GLStateManager.capabilities.OpenGL13;
private static final boolean enableCompass = MCPatcherForgeConfig.ExtendedHD.fancyCompass;
private static final boolean enableClock = MCPatcherForgeConfig.ExtendedHD.fancyClock;
private static final boolean useGL13 = gl13Supported && MCPatcherForgeConfig.ExtendedHD.useGL13;
@@ -148,7 +147,7 @@ public class FancyDial {
FancyDial instance = getInstance(icon);
return instance != null && instance.render(itemFrameRenderer);
} finally {
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFB);
GLStateManager.glBindFramebuffer(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFB);
GLAPI.glBindTexture(oldTexture);
}
}
@@ -603,13 +602,13 @@ public class FancyDial {
this.width = width;
this.height = height;
frameBuffer = EXTFramebufferObject.glGenFramebuffersEXT();
frameBuffer = GLStateManager.glGenFramebuffers();
if (frameBuffer < 0) {
throw new RuntimeException("could not get framebuffer object");
}
GLAPI.glBindTexture(texture);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer);
EXTFramebufferObject.glFramebufferTexture2DEXT(
GLStateManager.glBindFramebuffer(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer);
GLStateManager.glFramebufferTexture2D(
EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
GL11.GL_TEXTURE_2D,
@@ -618,7 +617,7 @@ public class FancyDial {
}
void bind() {
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer);
GLStateManager.glBindFramebuffer(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer);
GLStateManager.glPushAttrib(glAttributes);
GLStateManager.glViewport(x0, y0, width, height);
@@ -674,11 +673,11 @@ public class FancyDial {
GLStateManager.glEnable(GL11.GL_BLEND);
GLAPI.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
GLStateManager.glBindFramebuffer(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
}
void read(ByteBuffer buffer) {
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer);
GLStateManager.glBindFramebuffer(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer);
buffer.position(0);
GLStateManager.glReadPixels(x0, y0, width, height, MipmapHelper.TEX_FORMAT, MipmapHelper.TEX_DATA_TYPE, buffer);
}
@@ -704,7 +703,7 @@ public class FancyDial {
if (ownTexture) {
GLStateManager.glDeleteTextures(texture);
}
EXTFramebufferObject.glDeleteFramebuffersEXT(frameBuffer);
GLStateManager.glDeleteFramebuffers(frameBuffer);
}
}
@@ -11,7 +11,6 @@ import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
import org.lwjgl.opengl.EXTTextureLODBias;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.util.glu.GLU;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
@@ -47,10 +46,10 @@ public class MipmapHelper {
private static final Map<String, Boolean> mipmapType = new HashMap<>();
static {
mipmapSupported = GLContext.getCapabilities().OpenGL12;
mipmapSupported = GLStateManager.capabilities.OpenGL12;
useMipmap = mipmapSupported && mipmapEnabled && maxMipmapLevel > 0;
anisoSupported = GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic;
anisoSupported = GLStateManager.capabilities.GL_EXT_texture_filter_anisotropic;
if (anisoSupported) {
anisoMax = (int) GLStateManager.glGetFloat(EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
checkGLError("glGetFloat(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)");
@@ -59,7 +58,7 @@ public class MipmapHelper {
anisoMax = anisoLevel = 1;
}
lodSupported = GLContext.getCapabilities().GL_EXT_texture_lod_bias;
lodSupported = GLStateManager.capabilities.GL_EXT_texture_lod_bias;
if (lodSupported) {
lodBias = MCPatcherForgeConfig.ExtendedHD.lodBias;
} else {
@@ -1,13 +1,11 @@
package com.prupe.mcpatcher.mal.resource;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GLContext;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
public class GLAPI {
private static final boolean useGlBlendFuncSeparate = GLContext.getCapabilities().OpenGL14;
private static final boolean useGlBlendFuncSeparate = GLStateManager.capabilities.OpenGL14;
public static void glBindTexture(int texture) {
if (texture >= 0) {
@@ -100,6 +100,10 @@ public class SodiumGameOptions {
config.configPath = path;
if (config.advanced.streamingUploadStrategy == null) {
config.advanced.streamingUploadStrategy = StreamingUploader.UploadStrategy.MAP_BUFFER_RANGE;
}
// Clamp render-ahead to 0 if GL 3.2 fences aren't available
if (GLStateManager.capabilities == null || !GLStateManager.capabilities.OpenGL32) {
config.performance.cpuRenderAheadLimit = 0;
+42 -2
View File
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.Tags;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.InputEvent;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
@@ -17,6 +18,7 @@ import net.coderbot.iris.block_rendering.BlockRenderingSettings;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import net.coderbot.iris.celeritas.IrisCeleritasShaderProvider;
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.config.IrisConfig;
import net.coderbot.iris.gl.shader.StandardMacros;
import net.coderbot.iris.gui.screen.ShaderPackScreen;
@@ -113,11 +115,31 @@ public class Iris {
// Used in favor of queueDefaultShaderPackOptionValues() for resetting as the
// behavior is more concrete and therefore is more likely to repair a user's issues
private static boolean resetShaderPackOptions = false;
private static boolean loadShaderPackWhenPossible = false;
private static String IRIS_VERSION;
@Getter
private static boolean fallback;
public static boolean loadedIncompatiblePack() {
return DHCompat.lastPackIncompatible();
}
public static void loadShaderpackWhenPossible() {
loadShaderPackWhenPossible = true;
}
public static void tryLoadShaderpackWhenPossible() {
if (loadShaderPackWhenPossible) {
loadShaderPackWhenPossible = false;
try {
reload();
} catch (IOException e) {
logger.error("Error during deferred shader reload", e);
}
}
}
/**
* Lazy executor for parallelizing shader transformations during shader pack loading.
* Creates threads on demand and shuts down after a period of inactivity.
@@ -350,6 +372,7 @@ public class Iris {
* <p>This is called right before options are loaded, so we can add key bindings here.</p>
*/
public void onEarlyInitialize() {
DHCompat.run();
try {
if (!Files.exists(getShaderpacksDirectory())) {
Files.createDirectories(getShaderpacksDirectory());
@@ -395,8 +418,19 @@ public class Iris {
PBRTextureManager.INSTANCE.init();
// Only load the shader pack when we can access OpenGL
loadShaderpack();
boolean isDHLoaded;
try {
Class.forName("com.seibel.distanthorizons.DistantHorizonsTweaker");
isDHLoaded = true;
}
catch (Exception e) {
isDHLoaded = false;
}
// When DH is present, defer shaderpack loading until its init callback has run.
if (!isDHLoaded) {
loadShaderpack();
}
}
/**
@@ -721,6 +755,12 @@ public class Iris {
BlockRenderingSettings.INSTANCE.reloadRendererIfRequired();
}
if (loadedIncompatiblePack() && Minecraft.getMinecraft().thePlayer != null) {
Iris.logger.warn("Incompatible pack for DH!");
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.BOLD.toString() + EnumChatFormatting.RED + "This pack doesn't have DH support."));
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "Distant Horizons (DH) chunks won't show up. This isn't a bug, get another shader."));
}
}
/**
@@ -1,14 +1,129 @@
package net.coderbot.iris.compat.dh;
/**
* Stub implementation of Distant Horizons compatibility.
*/
public class DHCompat {
public int getDepthTex() {
return 0;
}
import com.gtnewhorizons.angelica.rendering.RenderingState;
import net.coderbot.iris.Iris;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.minecraft.client.Minecraft;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
public int getDepthTexNoTranslucent() {
return 0;
}
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
public class DHCompat {
private static boolean dhPresent;
private static boolean lastIncompatible;
private DHCompatInternal compatInternalInstance;
private final static Matrix4f tempProj = new Matrix4f();
public DHCompat(DeferredWorldRenderingPipeline pipeline, boolean renderDHShadow) {
if (pipeline == null) {
return;
}
try {
if (dhPresent) {
compatInternalInstance = new DHCompatInternal(pipeline, renderDHShadow);
lastIncompatible = compatInternalInstance.incompatiblePack();
}
} catch (Throwable e) {
lastIncompatible = false;
if (e instanceof InvocationTargetException ite) {
throw new RuntimeException("Unknown error loading Distant Horizons compatibility.", ite.getCause());
} else {
throw new RuntimeException("Unknown error loading Distant Horizons compatibility.", e);
}
}
}
public static Matrix4fc getProjection() {
Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();
if (!dhPresent) {
return projection;
}
return tempProj.setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), DHCompat.getNearPlane(), DHCompat.getFarPlane());
}
public static void run() {
try {
Class.forName("com.seibel.distanthorizons.DistantHorizonsTweaker");
dhPresent = true;
}
catch (Exception e) {
dhPresent = false;
}
try {
if (dhPresent) {
LodRendererEvents.setupEventHandlers();
}
} catch (Throwable e) {
dhPresent = false;
if (e instanceof ExceptionInInitializerError eiie) {
throw new RuntimeException("Failure loading DH compat.", eiie.getCause());
} else {
throw new RuntimeException("DH found, but one or more API methods are missing. Iris requires DH [2.0.4] or DH API version [1.1.0] or newer. Please make sure you are on the latest version of DH and Iris.", e);
}
}
}
public static boolean lastPackIncompatible() {
return dhPresent && hasRenderingEnabled() && lastIncompatible;
}
public static float getFarPlane() {
if (!dhPresent) return 0.01f;
return DHCompatInternal.getFarPlane();
}
public static float getNearPlane() {
if (!dhPresent) return 0.01f;
return DHCompatInternal.getNearPlane();
}
public static int getRenderDistance() {
if (!dhPresent) return Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16;
return DHCompatInternal.getRenderDistance();
}
public static boolean checkFrame() {
if (!dhPresent) {
return false;
}
return DHCompatInternal.checkFrame();
}
public static boolean hasRenderingEnabled() {
if (!dhPresent) {
return false;
}
return checkFrame();
}
public void clearPipeline() {
if (compatInternalInstance == null) return;
compatInternalInstance.clear();
}
public int getDepthTex() {
if (compatInternalInstance == null) return -1;
return compatInternalInstance.getStoredDepthTex();
}
public int getDepthTexNoTranslucent() {
if (compatInternalInstance == null) return -1;
return compatInternalInstance.getDepthTexNoTranslucent();
}
public DHCompatInternal getInstance() {
return compatInternalInstance;
}
}
@@ -0,0 +1,291 @@
package net.coderbot.iris.compat.dh;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import net.coderbot.iris.Iris;
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
import net.coderbot.iris.gl.texture.DepthBufferFormat;
import net.coderbot.iris.gl.texture.DepthCopyStrategy;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.rendertarget.DepthTexture;
import net.coderbot.iris.rendertarget.IRenderTargetExt;
import net.coderbot.iris.shaderpack.CloudSetting;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CapturedRenderingState;
import net.irisshaders.iris.api.v0.IrisApi;
import net.minecraft.client.Minecraft;
import org.lwjgl.opengl.GL11;
import java.io.IOException;
public class DHCompatInternal {
public static final DHCompatInternal SHADERLESS = new DHCompatInternal(null, false);
static boolean dhEnabled;
private static int guiScale = -1;
private final DeferredWorldRenderingPipeline pipeline;
public boolean shouldOverrideShadow;
public boolean shouldOverride;
private GlFramebuffer dhGenericFramebuffer;
private IrisLodRenderProgram solidProgram;
private IrisGenericRenderProgram genericShader;
private IrisLodRenderProgram translucentProgram;
private IrisLodRenderProgram shadowProgram;
private GlFramebuffer dhTerrainFramebuffer;
private DhFrameBufferWrapper dhTerrainFramebufferWrapper;
private GlFramebuffer dhWaterFramebuffer;
private GlFramebuffer dhShadowFramebuffer;
private DhFrameBufferWrapper dhShadowFramebufferWrapper;
private DepthTexture depthTexNoTranslucent;
private boolean translucentDepthDirty;
private int storedDepthTex = -1;
private boolean incompatible = false;
private int cachedVersion;
public DHCompatInternal(DeferredWorldRenderingPipeline pipeline, boolean dhShadowEnabled) {
this.pipeline = pipeline;
if (pipeline == null || !DhApi.Delayed.configs.graphics().renderingEnabled().getValue()) {
return;
}
if (pipeline.getDHTerrainShader().isEmpty() && pipeline.getDHWaterShader().isEmpty()) {
Iris.logger.warn("No DH shader found in this pack.");
incompatible = true;
return;
}
cachedVersion = ((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion();
createDepthTex(Minecraft.getMinecraft().getFramebuffer().framebufferWidth, Minecraft.getMinecraft().getFramebuffer().framebufferHeight);
translucentDepthDirty = true;
ProgramSource terrain = pipeline.getDHTerrainShader().get();
solidProgram = IrisLodRenderProgram.createProgram(terrain.getName(), false, false, terrain, pipeline.getCustomUniforms(), pipeline);
ProgramSource generic = pipeline.getDHGenericShader().get();
genericShader = IrisGenericRenderProgram.createProgram(generic.getName() + "_g", false, false, generic, pipeline.getCustomUniforms(), pipeline);
dhGenericFramebuffer = pipeline.createDHFramebuffer(generic, false);
if (pipeline.getDHWaterShader().isPresent()) {
ProgramSource water = pipeline.getDHWaterShader().get();
translucentProgram = IrisLodRenderProgram.createProgram(water.getName(), false, true, water, pipeline.getCustomUniforms(), pipeline);
dhWaterFramebuffer = pipeline.createDHFramebuffer(water, true);
}
if (pipeline.getDHShadowShader().isPresent() && dhShadowEnabled) {
ProgramSource shadow = pipeline.getDHShadowShader().get();
shadowProgram = IrisLodRenderProgram.createProgram(shadow.getName(), true, false, shadow, pipeline.getCustomUniforms(), pipeline);
if (pipeline.hasShadowRenderTargets()) {
dhShadowFramebuffer = pipeline.createDHFramebufferShadow(shadow);
dhShadowFramebufferWrapper = new DhFrameBufferWrapper(dhShadowFramebuffer);
}
shouldOverrideShadow = true;
} else {
shouldOverrideShadow = false;
}
dhTerrainFramebuffer = pipeline.createDHFramebuffer(terrain, false);
dhTerrainFramebufferWrapper = new DhFrameBufferWrapper(dhTerrainFramebuffer);
if (translucentProgram == null) {
translucentProgram = solidProgram;
}
shouldOverride = true;
}
public static int getDhBlockRenderDistance() {
if (DhApi.Delayed.configs == null || !dhEnabled) {
// Called before DH has finished setup
return Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16;
}
return DhApi.Delayed.configs.graphics().chunkRenderDistance().getValue() * 16;
}
public static int getRenderDistance() {
return getDhBlockRenderDistance();
}
public static float getFarPlane() {
if (DhApi.Delayed.configs == null) {
// Called before DH has finished setup
return 0;
}
int lodChunkDist = DhApi.Delayed.configs.graphics().chunkRenderDistance().getValue();
int lodBlockDist = lodChunkDist * 16;
// sqrt 2 to prevent the corners from being cut off
return (float) ((lodBlockDist + 512) * Math.sqrt(2));
}
public static float getNearPlane() {
if (DhApi.Delayed.renderProxy == null) {
// Called before DH has finished setup
return 0;
}
return DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(CapturedRenderingState.INSTANCE.getTickDelta());
}
public static boolean checkFrame() {
if (guiScale == -1) {
guiScale = Minecraft.getMinecraft().gameSettings.guiScale;
}
if (DhApi.Delayed.configs == null) return dhEnabled;
if ((dhEnabled != DhApi.Delayed.configs.graphics().renderingEnabled().getValue() || guiScale != Minecraft.getMinecraft().gameSettings.guiScale)
&& IrisApi.getInstance().isShaderPackInUse()) {
guiScale = Minecraft.getMinecraft().gameSettings.guiScale;
dhEnabled = DhApi.Delayed.configs.graphics().renderingEnabled().getValue();
try {
Iris.reload();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return dhEnabled;
}
public boolean incompatiblePack() {
return incompatible;
}
public void reconnectDHTextures(int depthTex) {
if (((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion() != cachedVersion) {
cachedVersion = ((IRenderTargetExt) Minecraft.getMinecraft().getFramebuffer()).iris$getDepthBufferVersion();
createDepthTex(Minecraft.getMinecraft().getFramebuffer().framebufferWidth, Minecraft.getMinecraft().getFramebuffer().framebufferHeight);
}
if (storedDepthTex != depthTex && dhTerrainFramebuffer != null) {
storedDepthTex = depthTex;
dhTerrainFramebuffer.addDepthAttachmentBypass(depthTex);
if (dhWaterFramebuffer != null) {
dhWaterFramebuffer.addDepthAttachmentBypass(depthTex);
}
if (dhGenericFramebuffer != null) {
dhGenericFramebuffer.addDepthAttachmentBypass(depthTex);
}
}
}
public void createDepthTex(int width, int height) {
if (depthTexNoTranslucent != null) {
depthTexNoTranslucent.destroy();
depthTexNoTranslucent = null;
}
translucentDepthDirty = true;
depthTexNoTranslucent = new DepthTexture(width, height, DepthBufferFormat.DEPTH32F);
}
public void clear() {
if (solidProgram != null) {
solidProgram.free();
solidProgram = null;
}
if (translucentProgram != null) {
translucentProgram.free();
translucentProgram = null;
}
if (shadowProgram != null) {
shadowProgram.free();
shadowProgram = null;
}
shouldOverrideShadow = false;
shouldOverride = false;
dhTerrainFramebuffer = null;
dhWaterFramebuffer = null;
dhShadowFramebuffer = null;
storedDepthTex = -1;
translucentDepthDirty = true;
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, dhTerrainFramebufferWrapper);
OverrideInjector.INSTANCE.unbind(IDhApiGenericObjectShaderProgram.class, genericShader);
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, dhShadowFramebufferWrapper);
dhTerrainFramebufferWrapper = null;
dhShadowFramebufferWrapper = null;
}
public void setModelPos(DhApiVec3f modelPos) {
solidProgram.bind();
solidProgram.setModelPos(modelPos);
translucentProgram.bind();
translucentProgram.setModelPos(modelPos);
solidProgram.bind();
}
public IrisLodRenderProgram getSolidShader() {
return solidProgram;
}
public GlFramebuffer getSolidFB() {
return dhTerrainFramebuffer;
}
public DhFrameBufferWrapper getSolidFBWrapper() {
return dhTerrainFramebufferWrapper;
}
public IrisLodRenderProgram getShadowShader() {
return shadowProgram;
}
public GlFramebuffer getShadowFB() {
return dhShadowFramebuffer;
}
public DhFrameBufferWrapper getShadowFBWrapper() {
return dhShadowFramebufferWrapper;
}
public IrisLodRenderProgram getTranslucentShader() {
if (translucentProgram == null) {
return solidProgram;
}
return translucentProgram;
}
public int getStoredDepthTex() {
return storedDepthTex;
}
public void copyTranslucents(int width, int height) {
if (translucentDepthDirty) {
translucentDepthDirty = false;
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, depthTexNoTranslucent.getTextureId());
dhTerrainFramebuffer.bindAsReadBuffer();
GLStateManager.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, DepthBufferFormat.DEPTH32F.getGlInternalFormat(), 0, 0, width, height, 0);
} else {
DepthCopyStrategy.fastest(false).copy(dhTerrainFramebuffer, storedDepthTex, null, depthTexNoTranslucent.getTextureId(), width, height);
}
}
public GlFramebuffer getTranslucentFB() {
return dhWaterFramebuffer;
}
public GlFramebuffer getGenericFB() {
return dhGenericFramebuffer;
}
public int getDepthTexNoTranslucent() {
if (depthTexNoTranslucent == null) return 0;
return depthTexNoTranslucent.getTextureId();
}
public IDhApiGenericObjectShaderProgram getGenericShader() {
return genericShader;
}
public boolean avoidRenderingClouds() {
return pipeline != null && (pipeline.getDHCloudSetting() == CloudSetting.OFF || (pipeline.getDHCloudSetting() == CloudSetting.DEFAULT && pipeline.getCloudSetting() == CloudSetting.OFF));
}
}
@@ -0,0 +1,55 @@
package net.coderbot.iris.compat.dh;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
import org.lwjgl.opengl.GL30;
public class DhFrameBufferWrapper implements IDhApiFramebuffer {
private final GlFramebuffer framebuffer;
public DhFrameBufferWrapper(GlFramebuffer framebuffer) {
this.framebuffer = framebuffer;
}
@Override
public boolean overrideThisFrame() {
return true;
}
@Override
public void bind() {
this.framebuffer.bind();
}
@Override
public void addDepthAttachment(int i, boolean b) {
// ignore
}
@Override
public int getId() {
return this.framebuffer.getId();
}
@Override
public int getStatus() {
this.bind();
int status = GLStateManager.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER);
return status;
}
@Override
public void addColorAttachment(int i, int i1) {
// ignore
}
@Override
public void destroy() {
// ignore
//this.framebuffer.destroy();
}
}
@@ -0,0 +1,351 @@
package net.coderbot.iris.compat.dh;
import com.google.common.primitives.Ints;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import com.mitchej123.lwjgl.MemoryStack;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import net.coderbot.iris.gl.blending.BufferBlendOverride;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.program.ProgramUniforms;
import net.coderbot.iris.gl.shader.GlShader;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
import net.coderbot.iris.pipeline.transform.PatchShaderType;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CommonUniforms;
import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
import net.irisshaders.iris.api.v0.IrisApi;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class IrisGenericRenderProgram implements IDhApiGenericObjectShaderProgram {
// Uniforms
public final int modelViewUniform;
public final int modelViewInverseUniform;
public final int projectionUniform;
public final int projectionInverseUniform;
public final int normalMatrix3fUniform;
// Fog/Clip Uniforms
private final int id;
private final ProgramUniforms uniforms;
private final CustomUniforms customUniforms;
private final ProgramSamplers samplers;
private final ProgramImages images;
private final BlendModeOverride blend;
private final BufferBlendOverride[] bufferBlendOverrides;
private final Matrix4f tempModel = new Matrix4f();
private final Matrix4f tempProj = new Matrix4f();
private final Matrix4f tempMat4 = new Matrix4f();
private final Matrix3f tempMat3 = new Matrix3f();
private final int instancedShaderOffsetChunkUniform;
private final int instancedShaderOffsetSubChunkUniform;
private final int instancedShaderCameraChunkPosUniform;
private final int instancedShaderCameraSubChunkPosUniform;
private final int instancedShaderProjectionModelViewMatrixUniform;
private final int va;
private final int uBlockLight;
private final int uSkyLight;
// This will bind AbstractVertexAttribute
private IrisGenericRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) {
id = GLStateManager.glCreateProgram();
GLStateManager.glBindAttribLocation(this.id, 0, "vPosition");
this.bufferBlendOverrides = bufferBlendOverrides;
GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex);
GLStateManager.glAttachShader(id, vert.getHandle());
GlShader tessCont = null;
if (tessControl != null) {
tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl);
GLStateManager.glAttachShader(id, tessCont.getHandle());
}
GlShader tessE = null;
if (tessEval != null) {
tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval);
GLStateManager.glAttachShader(id, tessE.getHandle());
}
GlShader geom = null;
if (geometry != null) {
geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry);
GLStateManager.glAttachShader(id, geom.getHandle());
}
GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment);
GLStateManager.glAttachShader(id, frag.getHandle());
GLStateManager.glLinkProgram(this.id);
int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
if (status != 1) {
String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999);
this.free();
throw new RuntimeException(message);
} else {
GLStateManager.glUseProgram(this.id);
}
vert.destroy();
frag.destroy();
if (tessCont != null) tessCont.destroy();
if (tessE != null) tessE.destroy();
if (geom != null) geom.destroy();
blend = override;
ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id);
ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX);
customUniforms.assignTo(uniformBuilder);
BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder);
ProgramImages.Builder builder = ProgramImages.builder(id);
pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder,
isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(),
isShadowPass, true, true, false);
customUniforms.mapholderToPass(uniformBuilder, this);
this.uniforms = uniformBuilder.buildUniforms();
this.customUniforms = customUniforms;
samplers = samplerBuilder.build();
images = builder.build();
this.va = GLStateManager.glGenVertexArrays();
GLStateManager.glBindVertexArray(va);
GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GLStateManager.glEnableVertexAttribArray(0);
projectionUniform = tryGetUniformLocation2("iris_ProjectionMatrix");
projectionInverseUniform = tryGetUniformLocation2("iris_ProjectionMatrixInverse");
modelViewUniform = tryGetUniformLocation2("iris_ModelViewMatrix");
modelViewInverseUniform = tryGetUniformLocation2("iris_ModelViewMatrixInverse");
normalMatrix3fUniform = tryGetUniformLocation2("iris_NormalMatrix");
this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation2("uOffsetChunk");
this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation2("uOffsetSubChunk");
this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation2("uCameraPosChunk");
this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation2("uCameraPosSubChunk");
this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation2("uProjectionMvm");
this.uBlockLight = this.tryGetUniformLocation2("uBlockLight");
this.uSkyLight = this.tryGetUniformLocation2("uSkyLight");
}
public static IrisGenericRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) {
Map<PatchShaderType, String> transformed = TransformPatcher.patchDHGeneric(
name,
source.getVertexSource().orElseThrow(RuntimeException::new),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getGeometrySource().orElse(null),
source.getFragmentSource().orElseThrow(RuntimeException::new),
pipeline.getTextureMap());
String vertex = transformed.get(PatchShaderType.VERTEX);
String tessControl = transformed.get(PatchShaderType.TESS_CONTROL);
String tessEval = transformed.get(PatchShaderType.TESS_EVAL);
String geometry = transformed.get(PatchShaderType.GEOMETRY);
String fragment = transformed.get(PatchShaderType.FRAGMENT);
PatchedShaderPrinter.debugPatchedShaders(source.getName() + "_g", vertex, geometry, tessControl, tessEval, fragment);
List<BufferBlendOverride> bufferOverrides = new ArrayList<>();
source.getDirectives().getBufferBlendOverrides().forEach(information -> {
int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex());
if (index > -1) {
bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode()));
}
});
return new IrisGenericRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline);
}
// Noise Uniforms
private static int getChunkPosFromDouble(double value) {
return (int) Math.floor(value / 16);
}
private static float getSubChunkPosFromDouble(double value) {
double chunkPos = Math.floor(value / 16);
return (float) (value - chunkPos * 16);
}
public int tryGetUniformLocation2(CharSequence name) {
return GLStateManager.glGetUniformLocation(this.id, name);
}
public void setUniform(int index, Matrix4f matrix) {
if (index == -1 || matrix == null) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(16);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix4(index, false, buffer);
}
}
public void setUniform(int index, Matrix3f matrix) {
if (index == -1) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(9);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix3(index, false, buffer);
}
}
// Override ShaderProgram.bind()
public void bind(DhApiRenderParam renderParam) {
GLStateManager.glBindVertexArray(va);
GLStateManager.glUseProgram(id);
if (blend != null) blend.apply();
for (BufferBlendOverride override : bufferBlendOverrides) {
override.apply();
}
toJOML(tempModel, renderParam.dhModelViewMatrix);
toJOML(tempProj, renderParam.dhProjectionMatrix);
setUniform(modelViewUniform, tempModel);
setUniform(projectionUniform, tempProj);
this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, tempMat4.set(tempProj).mul(tempModel));
tempModel.invert();
tempProj.invert();
setUniform(modelViewInverseUniform, tempModel);
setUniform(projectionInverseUniform, tempProj);
setUniform(normalMatrix3fUniform, tempModel.transpose3x3(tempMat3));
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT);
DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture();
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId());
samplers.update();
uniforms.update();
customUniforms.push(this);
images.update();
}
public void unbind() {
GLStateManager.glBindVertexArray(0);
GLStateManager.glUseProgram(0);
ProgramUniforms.clearActiveUniforms();
ProgramSamplers.clearActiveSamplers();
BlendModeOverride.restore();
}
@Override
public void bindVertexBuffer(int i) {
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, i);
GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 12, 0);
}
@Override
public boolean overrideThisFrame() {
return IrisApi.getInstance().isShaderPackInUse();
}
@Override
public int getId() {
return id;
}
public void free() {
GLStateManager.glDeleteProgram(id);
}
public void fillIndirectUniformData(DhApiRenderParam dhApiRenderParam, DhApiRenderableBoxGroupShading dhApiRenderableBoxGroupShading, IDhApiRenderableBoxGroup boxGroup, DhApiVec3d camPos) {
bind(dhApiRenderParam);
GLStateManager.enableDepthTest();
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
this.setUniform(this.instancedShaderOffsetChunkUniform,
getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
);
this.setUniform(this.instancedShaderOffsetSubChunkUniform,
getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
);
this.setUniform(this.instancedShaderCameraChunkPosUniform,
getChunkPosFromDouble(camPos.x),
getChunkPosFromDouble(camPos.y),
getChunkPosFromDouble(camPos.z)
);
this.setUniform(this.instancedShaderCameraSubChunkPosUniform,
getSubChunkPosFromDouble(camPos.x),
getSubChunkPosFromDouble(camPos.y),
getSubChunkPosFromDouble(camPos.z)
);
this.setUniform(this.uBlockLight,
boxGroup.getBlockLight());
this.setUniform(this.uSkyLight,
boxGroup.getSkyLight());
}
@Override
public void fillSharedDirectUniformData(DhApiRenderParam dhApiRenderParam, DhApiRenderableBoxGroupShading dhApiRenderableBoxGroupShading, IDhApiRenderableBoxGroup iDhApiRenderableBoxGroup, DhApiVec3d dhApiVec3d) {
throw new IllegalStateException("Only indirect is supported with Iris.");
}
@Override
public void fillDirectUniformData(DhApiRenderParam dhApiRenderParam, IDhApiRenderableBoxGroup iDhApiRenderableBoxGroup, DhApiRenderableBox dhApiRenderableBox, DhApiVec3d dhApiVec3d) {
throw new IllegalStateException("Only indirect is supported with Iris.");
}
private void toJOML(Matrix4f target, DhApiMat4f mat4f) {
target.setTransposed(mat4f.getValuesAsArray());
}
private void setUniform(int index, int value) {
GLStateManager.glUniform1i(index, value);
}
private void setUniform(int index, float value) {
GLStateManager.glUniform1f(index, value);
}
private void setUniform(int index, float x, float y, float z) {
GLStateManager.glUniform3f(index, x, y, z);
}
private void setUniform(int index, int x, int y, int z) {
GLStateManager.glUniform3i(index, x, y, z);
}
}
@@ -0,0 +1,266 @@
package net.coderbot.iris.compat.dh;
import com.google.common.primitives.Ints;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import com.mitchej123.lwjgl.MemoryStack;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import net.coderbot.iris.gl.blending.BufferBlendOverride;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.program.ProgramUniforms;
import net.coderbot.iris.gl.shader.GlShader;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.gl.texture.TextureType;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
import net.coderbot.iris.pipeline.transform.PatchShaderType;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CommonUniforms;
import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL32;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class IrisLodRenderProgram {
// Uniforms
public final int modelOffsetUniform;
public final int worldYOffsetUniform;
public final int mircoOffsetUniform;
public final int modelViewUniform;
public final int modelViewInverseUniform;
public final int projectionUniform;
public final int projectionInverseUniform;
public final int normalMatrix3fUniform;
// Fog/Clip Uniforms
public final int clipDistanceUniform;
private final int id;
private final ProgramUniforms uniforms;
private final CustomUniforms customUniforms;
private final ProgramSamplers samplers;
private final ProgramImages images;
private final BlendModeOverride blend;
private final BufferBlendOverride[] bufferBlendOverrides;
private final Matrix4f tempMat4a = new Matrix4f();
private final Matrix4f tempMat4b = new Matrix4f();
private final Matrix3f tempMat3 = new Matrix3f();
// This will bind AbstractVertexAttribute
private IrisLodRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) {
id = GLStateManager.glCreateProgram();
GLStateManager.glBindAttribLocation(this.id, 0, "vPosition");
GLStateManager.glBindAttribLocation(this.id, 1, "iris_color");
GLStateManager.glBindAttribLocation(this.id, 2, "irisExtra");
this.bufferBlendOverrides = bufferBlendOverrides;
GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex);
GLStateManager.glAttachShader(id, vert.getHandle());
GlShader tessCont = null;
if (tessControl != null) {
tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl);
GLStateManager.glAttachShader(id, tessCont.getHandle());
}
GlShader tessE = null;
if (tessEval != null) {
tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval);
GLStateManager.glAttachShader(id, tessE.getHandle());
}
GlShader geom = null;
if (geometry != null) {
geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry);
GLStateManager.glAttachShader(id, geom.getHandle());
}
GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment);
GLStateManager.glAttachShader(id, frag.getHandle());
GLStateManager.glLinkProgram(this.id);
int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
if (status != 1) {
String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999);
this.free();
throw new RuntimeException(message);
} else {
GLStateManager.glUseProgram(this.id);
}
vert.destroy();
frag.destroy();
if (tessCont != null) tessCont.destroy();
if (tessE != null) tessE.destroy();
if (geom != null) geom.destroy();
blend = override;
ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id);
ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX);
customUniforms.assignTo(uniformBuilder);
BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder);
ProgramImages.Builder builder = ProgramImages.builder(id);
pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder,
isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(),
isShadowPass, true, true, false);
customUniforms.mapholderToPass(uniformBuilder, this);
this.uniforms = uniformBuilder.buildUniforms();
this.customUniforms = customUniforms;
samplers = samplerBuilder.build();
images = builder.build();
modelOffsetUniform = tryGetUniformLocation2("modelOffset");
worldYOffsetUniform = tryGetUniformLocation2("worldYOffset");
mircoOffsetUniform = tryGetUniformLocation2("mircoOffset");
projectionUniform = tryGetUniformLocation2("iris_ProjectionMatrix");
projectionInverseUniform = tryGetUniformLocation2("iris_ProjectionMatrixInverse");
modelViewUniform = tryGetUniformLocation2("iris_ModelViewMatrix");
modelViewInverseUniform = tryGetUniformLocation2("iris_ModelViewMatrixInverse");
normalMatrix3fUniform = tryGetUniformLocation2("iris_NormalMatrix");
// Fog/Clip Uniforms
clipDistanceUniform = tryGetUniformLocation2("clipDistance");
}
public static IrisLodRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) {
Map<PatchShaderType, String> transformed = TransformPatcher.patchDHTerrain(
name,
source.getVertexSource().orElseThrow(RuntimeException::new),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getGeometrySource().orElse(null),
source.getFragmentSource().orElseThrow(RuntimeException::new),
pipeline.getTextureMap());
String vertex = transformed.get(PatchShaderType.VERTEX);
String tessControl = transformed.get(PatchShaderType.TESS_CONTROL);
String tessEval = transformed.get(PatchShaderType.TESS_EVAL);
String geometry = transformed.get(PatchShaderType.GEOMETRY);
String fragment = transformed.get(PatchShaderType.FRAGMENT);
PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, tessControl, tessEval, fragment);
List<BufferBlendOverride> bufferOverrides = new ArrayList<>();
source.getDirectives().getBufferBlendOverrides().forEach(information -> {
int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex());
if (index > -1) {
bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode()));
}
});
return new IrisLodRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline);
}
// Noise Uniforms
public int tryGetUniformLocation2(CharSequence name) {
return GLStateManager.glGetUniformLocation(this.id, name);
}
public void setUniform(int index, Matrix4fc matrix) {
if (index == -1 || matrix == null) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(16);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix4(index, false, buffer);
}
}
public void setUniform(int index, Matrix3f matrix) {
if (index == -1) return;
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buffer = stack.callocFloat(9);
matrix.get(buffer);
buffer.rewind();
GLStateManager.glUniformMatrix3(index, false, buffer);
}
}
// Override ShaderProgram.bind()
public void bind() {
GLStateManager.glUseProgram(id);
if (blend != null) blend.apply();
for (BufferBlendOverride override : bufferBlendOverrides) {
override.apply();
}
}
public void unbind() {
GLStateManager.glUseProgram(0);
ProgramUniforms.clearActiveUniforms();
ProgramSamplers.clearActiveSamplers();
BlendModeOverride.restore();
}
public void free() {
GLStateManager.glDeleteProgram(id);
}
public void fillUniformData(Matrix4fc projection, Matrix4fc modelView, int worldYOffset, float partialTicks) {
GLStateManager.glUseProgram(id);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT);
DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture();
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId());
setUniform(modelViewUniform, modelView);
setUniform(modelViewInverseUniform, modelView.invert(tempMat4a));
setUniform(projectionUniform, projection);
setUniform(projectionInverseUniform, projection.invert(tempMat4b));
setUniform(normalMatrix3fUniform, tempMat4a.set(modelView).invert().transpose3x3(tempMat3));
setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset
// setUniform(skyLightUniform, skyLight);
if (worldYOffsetUniform != -1) setUniform(worldYOffsetUniform, (float) worldYOffset);
// Fog/Clip Uniforms
float dhNearClipDistance = DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(partialTicks);
setUniform(clipDistanceUniform, dhNearClipDistance);
samplers.update();
uniforms.update();
customUniforms.push(this);
images.update();
}
private void setUniform(int index, float value) {
GLStateManager.glUniform1f(index, value);
}
public void setModelPos(DhApiVec3f modelPos) {
setUniform(modelOffsetUniform, modelPos);
}
private void setUniform(int index, DhApiVec3f pos) {
GLStateManager.glUniform3f(index, pos.x, pos.y, pos.z);
}
}
@@ -0,0 +1,383 @@
package net.coderbot.iris.compat.dh;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogDrawMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeApplyShaderRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDeferredRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderCleanupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderSetupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeTextureClearEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiColorDepthTextureCreatedEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import net.coderbot.iris.Iris;
import net.coderbot.iris.pipeline.ShadowRenderer;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
import net.coderbot.iris.shadows.ShadowRenderingState;
import net.coderbot.iris.uniforms.CapturedRenderingState;
import net.irisshaders.iris.api.v0.IrisApi;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
public class LodRendererEvents {
// TODO: Query actual world min height for Cubic Chunks compatibility
private static final int WORLD_MIN_Y = 0;
private static boolean eventHandlersBound = false;
private static boolean atTranslucent = false;
private static int textureWidth;
private static int textureHeight;
private static final Matrix4f tempMat4 = new Matrix4f();
// constructor //
public static void setupEventHandlers() {
if (!eventHandlersBound) {
eventHandlersBound = true;
Iris.logger.info("Queuing DH event binding...");
DhApiAfterDhInitEvent beforeCleanupEvent = new DhApiAfterDhInitEvent() {
@Override
public void afterDistantHorizonsInit(DhApiEventParam<Void> event) {
Iris.logger.info("DH Ready, binding Iris event handlers...");
Iris.loadShaderpackWhenPossible();
setupSetDeferredBeforeRenderingEvent();
setupReconnectDepthTextureEvent();
setupGenericEvent();
setupCreateDepthTextureEvent();
setupTransparentRendererEventCancling();
setupBeforeBufferClearEvent();
setupBeforeRenderCleanupEvent();
beforeBufferRenderEvent();
setupBeforeRenderFrameBufferBinding();
setupBeforeRenderPassEvent();
setupBeforeApplyShaderEvent();
DHCompatInternal.dhEnabled = DhApi.Delayed.configs.graphics().renderingEnabled().getValue();
Iris.logger.info("DH Iris events bound.");
}
};
DhApi.events.bind(DhApiAfterDhInitEvent.class, beforeCleanupEvent);
}
}
// setup event handlers //
private static void setupSetDeferredBeforeRenderingEvent() {
DhApiBeforeRenderEvent beforeRenderEvent = new DhApiBeforeRenderEvent() {
// this event is called before DH starts any rendering prep
// canceling it will prevent DH from rendering for that frame
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
DhApi.Delayed.renderProxy.setDeferTransparentRendering(IrisApi.getInstance().isShaderPackInUse() && getInstance().shouldOverride);
DhApi.Delayed.configs.graphics().fog().drawMode().setValue(getInstance().shouldOverride ? EDhApiFogDrawMode.FOG_DISABLED : EDhApiFogDrawMode.FOG_ENABLED);
}
};
DhApi.events.bind(DhApiBeforeRenderEvent.class, beforeRenderEvent);
}
private static void setupReconnectDepthTextureEvent() {
DhApiBeforeTextureClearEvent beforeRenderEvent = new DhApiBeforeTextureClearEvent() {
@Override
public void beforeClear(DhApiCancelableEventParam<DhApiRenderParam> event) {
var getResult = DhApi.Delayed.renderProxy.getDhDepthTextureId();
if (getResult.success) {
int depthTextureId = getResult.payload;
getInstance().reconnectDHTextures(depthTextureId);
}
}
};
DhApi.events.bind(DhApiBeforeTextureClearEvent.class, beforeRenderEvent);
}
private static void setupGenericEvent() {
DhApiBeforeGenericRenderSetupEvent beforeRenderEvent = new DhApiBeforeGenericRenderSetupEvent() {
@Override
public void beforeSetup(DhApiEventParam<DhApiRenderParam> dhApiEventParam) {
if (getInstance().getGenericFB() != null) {
getInstance().getGenericFB().bind();
}
}
};
DhApiBeforeGenericObjectRenderEvent beforeDrawEvent = new DhApiBeforeGenericObjectRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<EventParam> dhApiCancelableEventParam) {
if (dhApiCancelableEventParam.value.resourceLocationPath.equalsIgnoreCase("Clouds")) {
if (getInstance().avoidRenderingClouds()) {
dhApiCancelableEventParam.cancelEvent();
}
}
}
};
DhApi.events.bind(DhApiBeforeGenericRenderSetupEvent.class, beforeRenderEvent);
DhApi.events.bind(DhApiBeforeGenericObjectRenderEvent.class, beforeDrawEvent);
}
private static DHCompatInternal getInstance() {
return Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::getDHCompat).map(DHCompat::getInstance).orElse(DHCompatInternal.SHADERLESS);
}
private static void setupCreateDepthTextureEvent() {
DhApiColorDepthTextureCreatedEvent beforeRenderEvent = new DhApiColorDepthTextureCreatedEvent() {
@Override
public void onResize(DhApiEventParam<EventParam> input) {
textureWidth = input.value.newWidth;
textureHeight = input.value.newHeight;
}
};
DhApi.events.bind(DhApiColorDepthTextureCreatedEvent.class, beforeRenderEvent);
}
private static void setupTransparentRendererEventCancling() {
DhApiBeforeRenderEvent beforeRenderEvent = new DhApiBeforeRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && (!getInstance().shouldOverrideShadow)) {
event.cancelEvent();
}
}
};
DhApiBeforeDeferredRenderEvent beforeRenderEvent2 = new DhApiBeforeDeferredRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && (!getInstance().shouldOverrideShadow)) {
event.cancelEvent();
}
}
};
DhApi.events.bind(DhApiBeforeRenderEvent.class, beforeRenderEvent);
DhApi.events.bind(DhApiBeforeDeferredRenderEvent.class, beforeRenderEvent2);
}
private static void setupBeforeRenderCleanupEvent() {
DhApiBeforeRenderCleanupEvent beforeCleanupEvent = new DhApiBeforeRenderCleanupEvent() {
@Override
public void beforeCleanup(DhApiEventParam<DhApiRenderParam> event) {
if (getInstance().shouldOverride) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
getInstance().getShadowShader().unbind();
} else {
getInstance().getSolidShader().unbind();
if (atTranslucent) {
GLStateManager.enableCull();
}
}
}
}
};
DhApi.events.bind(DhApiBeforeRenderCleanupEvent.class, beforeCleanupEvent);
}
private static void setupBeforeBufferClearEvent() {
DhApiBeforeTextureClearEvent beforeCleanupEvent = new DhApiBeforeTextureClearEvent() {
@Override
public void beforeClear(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (event.value.renderPass == EDhApiRenderPass.OPAQUE) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
event.cancelEvent();
} else if (getInstance().shouldOverride) {
GLStateManager.glClear(GL11.GL_DEPTH_BUFFER_BIT);
event.cancelEvent();
}
}
}
};
DhApi.events.bind(DhApiBeforeTextureClearEvent.class, beforeCleanupEvent);
}
private static void beforeBufferRenderEvent() {
DhApiBeforeBufferRenderEvent beforeCleanupEvent = new DhApiBeforeBufferRenderEvent() {
@Override
public void beforeRender(DhApiEventParam<EventParam> input) {
DHCompatInternal instance = getInstance();
if (instance.shouldOverride) {
DhApiVec3f modelPos = input.value.modelPos;
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().bind();
instance.getShadowShader().setModelPos(modelPos);
} else if (atTranslucent) {
instance.getTranslucentShader().bind();
instance.getTranslucentShader().setModelPos(modelPos);
} else {
instance.getSolidShader().bind();
instance.getSolidShader().setModelPos(modelPos);
}
}
}
};
DhApi.events.bind(DhApiBeforeBufferRenderEvent.class, beforeCleanupEvent);
}
private static void setupBeforeRenderFrameBufferBinding() {
DhApiBeforeRenderSetupEvent beforeRenderPassEvent = new DhApiBeforeRenderSetupEvent() {
@Override
public void beforeSetup(DhApiEventParam<DhApiRenderParam> event) {
DHCompatInternal instance = getInstance();
OverrideInjector.INSTANCE.unbind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM);
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getShadowFBWrapper());
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getSolidFBWrapper());
OverrideInjector.INSTANCE.unbind(IDhApiGenericObjectShaderProgram.class, instance.getGenericShader());
if (instance.shouldOverride) {
if (instance.getGenericShader() != null) {
OverrideInjector.INSTANCE.bind(IDhApiGenericObjectShaderProgram.class, instance.getGenericShader());
}
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() && instance.shouldOverrideShadow) {
OverrideInjector.INSTANCE.bind(IDhApiFramebuffer.class, instance.getShadowFBWrapper());
OverrideInjector.INSTANCE.bind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM);
} else {
OverrideInjector.INSTANCE.bind(IDhApiFramebuffer.class, instance.getSolidFBWrapper());
}
}
}
};
DhApi.events.bind(DhApiBeforeRenderSetupEvent.class, beforeRenderPassEvent);
}
private static void setupBeforeRenderPassEvent() {
DhApiBeforeRenderPassEvent beforeCleanupEvent = new DhApiBeforeRenderPassEvent() {
@Override
public void beforeRender(DhApiEventParam<DhApiRenderParam> event) {
DHCompatInternal instance = getInstance();
// config overrides
if (instance.shouldOverride) {
DhApi.Delayed.configs.graphics().ambientOcclusion().enabled().setValue(false);
DhApi.Delayed.configs.graphics().fog().drawMode().setValue(EDhApiFogDrawMode.FOG_DISABLED);
if (event.value.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT) {
Iris.logger.error("Unexpected; somehow the Opaque + Translucent pass ran with shaders on.");
}
} else {
DhApi.Delayed.configs.graphics().ambientOcclusion().enabled().clearValue();
DhApi.Delayed.configs.graphics().fog().drawMode().clearValue();
}
// cleanup
if (event.value.renderPass == EDhApiRenderPass.OPAQUE) {
if (instance.shouldOverride) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().bind();
} else {
instance.getSolidShader().bind();
}
atTranslucent = false;
}
}
// opaque
if (event.value.renderPass == EDhApiRenderPass.OPAQUE) {
float partialTicks = event.value.partialTicks;
if (instance.shouldOverride) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().fillUniformData(
ShadowRenderer.PROJECTION, ShadowRenderer.MODELVIEW,
WORLD_MIN_Y,
partialTicks);
} else {
Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();;
instance.getSolidShader().fillUniformData(
tempMat4.setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), event.value.nearClipPlane, event.value.farClipPlane),
RenderingState.INSTANCE.getModelViewMatrix(),
WORLD_MIN_Y,
partialTicks);
}
}
}
// transparent
if (event.value.renderPass == EDhApiRenderPass.TRANSPARENT) {
float partialTicks = event.value.partialTicks;
int depthTextureId = DhApi.Delayed.renderProxy.getDhDepthTextureId().payload;
if (instance.shouldOverrideShadow && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
instance.getShadowShader().bind();
instance.getShadowFB().bind();
atTranslucent = true;
return;
}
if (instance.shouldOverride && instance.getTranslucentFB() != null) {
instance.copyTranslucents(textureWidth, textureHeight);
instance.getTranslucentShader().bind();
Matrix4f projection = RenderingState.INSTANCE.getProjectionMatrix();
GLStateManager.disableCull();
instance.getTranslucentShader().fillUniformData(
new Matrix4f().setPerspective(projection.perspectiveFov(), projection.m11() / projection.m00(), event.value.nearClipPlane, event.value.farClipPlane),
RenderingState.INSTANCE.getModelViewMatrix(),
WORLD_MIN_Y,
partialTicks);
instance.getTranslucentFB().bind();
}
atTranslucent = true;
}
}
};
DhApi.events.bind(DhApiBeforeRenderPassEvent.class, beforeCleanupEvent);
}
private static void setupBeforeApplyShaderEvent() {
DhApiBeforeApplyShaderRenderEvent beforeApplyShaderEvent = new DhApiBeforeApplyShaderRenderEvent() {
@Override
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event) {
if (IrisApi.getInstance().isShaderPackInUse()) {
DHCompatInternal instance = getInstance();
OverrideInjector.INSTANCE.unbind(IDhApiShadowCullingFrustum.class, (IDhApiOverrideable) ShadowRenderer.FRUSTUM);
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getShadowFBWrapper());
OverrideInjector.INSTANCE.unbind(IDhApiFramebuffer.class, instance.getSolidFBWrapper());
event.cancelEvent();
}
}
};
DhApi.events.bind(DhApiBeforeApplyShaderRenderEvent.class, beforeApplyShaderEvent);
}
}
@@ -33,12 +33,18 @@ public class IrisConfig {
*/
private boolean disableUpdateMessage;
/**
* If debug features should be enabled. Gives much more detailed OpenGL error outputs at the cost of performance.
*/
private boolean enableDebugOptions;
private final Path propertiesPath;
public IrisConfig(Path propertiesPath) {
shaderPackName = null;
enableShaders = true;
disableUpdateMessage = false;
enableDebugOptions = false;
this.propertiesPath = propertiesPath;
}
@@ -103,6 +109,10 @@ public class IrisConfig {
this.enableShaders = enabled;
}
public boolean areDebugOptionsEnabled() {
return enableDebugOptions;
}
/**
* loads the config file and then populates the string, int, and boolean entries with the parsed entries
*
@@ -121,6 +131,7 @@ public class IrisConfig {
}
shaderPackName = properties.getProperty("shaderPack");
enableShaders = !"false".equals(properties.getProperty("enableShaders"));
enableDebugOptions = "true".equals(properties.getProperty("enableDebugOptions"));
disableUpdateMessage = "true".equals(properties.getProperty("disableUpdateMessage"));
// TODO: GUI
try {
@@ -147,6 +158,7 @@ public class IrisConfig {
final Properties properties = new Properties();
properties.setProperty("shaderPack", getShaderPackName().orElse(""));
properties.setProperty("enableShaders", enableShaders ? "true" : "false");
properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false");
properties.setProperty("disableUpdateMessage", disableUpdateMessage ? "true" : "false");
properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance));
// NB: This uses ISO-8859-1 with unicode escapes as the encoding
@@ -8,6 +8,7 @@ public enum RenderCondition {
CLOUDS,
DESTROY,
BLOCK_ENTITIES,
BLOCK_ENTITIES_TRANSLUCENT,
BEACON_BEAM,
ENTITIES,
ENTITIES_TRANSLUCENT,
@@ -45,6 +45,12 @@ public class GlFramebuffer extends GlResource {
this.hasDepthAttachment = true;
}
public void addDepthAttachmentBypass(int texture) {
final int fb = getGlId();
RenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0);
this.hasDepthAttachment = true;
}
public void addColorAttachment(int index, int texture) {
final int fb = getGlId();
@@ -2,6 +2,7 @@ package net.coderbot.iris.gl.program;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import java.nio.IntBuffer;
import java.util.ArrayList;
@@ -189,7 +190,7 @@ public class ProgramUniforms {
public ProgramUniforms buildUniforms() {
// Check for any unsupported uniforms and warn about them so that we can easily figure out what uniforms we need to add.
final int activeUniforms = GL20.glGetProgrami(program, GL20.GL_ACTIVE_UNIFORMS);
final int activeUniforms = GLStateManager.glGetProgrami(program, GL20.GL_ACTIVE_UNIFORMS);
IntBuffer sizeType = BufferUtils.createIntBuffer(2);
for (int index = 0; index < activeUniforms; index++) {
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.angelica.Tags;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import cpw.mods.fml.common.Loader;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.parsing.BiomeCategories;
import net.coderbot.iris.pipeline.HandRenderer;
import net.coderbot.iris.pipeline.WorldRenderingPhase;
@@ -77,10 +78,32 @@ public class StandardMacros {
define(standardDefines, "MC_SPECULAR_MAP");
define(standardDefines, "MC_RENDER_QUALITY", "1.0");
define(standardDefines, "MC_SHADOW_QUALITY", "1.0");
define(standardDefines, "IS_ANGELICA");
if (AngelicaConfig.defineIsIris) {
define(standardDefines, "IS_IRIS");
}
define(standardDefines, "IS_ANGELICA");
if (AngelicaConfig.defineIsIris) {
define(standardDefines, "IS_IRIS");
}
if (DHCompat.hasRenderingEnabled()) {
define(standardDefines, "DISTANT_HORIZONS");
}
define(standardDefines, "DH_BLOCK_UNKNOWN", String.valueOf(0));
define(standardDefines, "DH_BLOCK_LEAVES", String.valueOf(1));
define(standardDefines, "DH_BLOCK_STONE", String.valueOf(2));
define(standardDefines, "DH_BLOCK_WOOD", String.valueOf(3));
define(standardDefines, "DH_BLOCK_METAL", String.valueOf(4));
define(standardDefines, "DH_BLOCK_DIRT", String.valueOf(5));
define(standardDefines, "DH_BLOCK_LAVA", String.valueOf(6));
define(standardDefines, "DH_BLOCK_DEEPSLATE", String.valueOf(7));
define(standardDefines, "DH_BLOCK_SNOW", String.valueOf(8));
define(standardDefines, "DH_BLOCK_SAND", String.valueOf(9));
define(standardDefines, "DH_BLOCK_TERRACOTTA", String.valueOf(10));
define(standardDefines, "DH_BLOCK_NETHER_STONE", String.valueOf(11));
define(standardDefines, "DH_BLOCK_WATER", String.valueOf(12));
define(standardDefines, "DH_BLOCK_GRASS", String.valueOf(13));
define(standardDefines, "DH_BLOCK_AIR", String.valueOf(14));
define(standardDefines, "DH_BLOCK_ILLUMINATED", String.valueOf(15));
define(standardDefines, "ANGELICA_VERSION", makeAngelicaVersion());
define(standardDefines, "MC_HAND_DEPTH", Float.toString(HandRenderer.DEPTH));
@@ -3,6 +3,7 @@ package net.coderbot.iris.gl.uniform;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector2i;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import org.joml.Vector4f;
import org.joml.Vector4i;
@@ -43,7 +44,7 @@ public interface DynamicLocationalUniformHolder extends LocationalUniformHolder,
return this;
}
default DynamicUniformHolder uniform3i(String name, Supplier<Vector3i> value, ValueUpdateNotifier notifier) {
default DynamicUniformHolder uniform3i(String name, Supplier<Vector3ic> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC3I).ifPresent(id -> addDynamicUniform(new Vector3IntegerJomlUniform(id, value, notifier), notifier));
return this;
@@ -3,6 +3,7 @@ package net.coderbot.iris.gl.uniform;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector2i;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import org.joml.Vector4f;
import org.joml.Vector4i;
@@ -16,7 +17,7 @@ public interface DynamicUniformHolder extends UniformHolder {
DynamicUniformHolder uniform1f(String name, DoubleSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform2i(String name, Supplier<Vector2i> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform3i(String name, Supplier<Vector3i> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform3i(String name, Supplier<Vector3ic> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4f(String name, Supplier<Vector4f> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4fArray(String name, Supplier<float[]> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4i(String name, Supplier<Vector4i> value, ValueUpdateNotifier notifier);
@@ -2,11 +2,14 @@ package net.coderbot.iris.gl.uniform;
import net.minecraft.util.Vec3;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector2f;
import org.joml.Vector2i;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import org.joml.Vector4f;
import java.util.OptionalInt;
@@ -70,14 +73,14 @@ public interface LocationalUniformHolder extends UniformHolder {
}
@Override
default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3f> value) {
default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3fc> value) {
location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, new Vector3Uniform(id, value)));
return this;
}
@Override
default LocationalUniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3i> value) {
default LocationalUniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3ic> value) {
location(name, UniformType.VEC3I).ifPresent(id -> addUniform(updateFrequency, new Vector3IntegerJomlUniform(id, value)));
return this;
@@ -119,7 +122,7 @@ public interface LocationalUniformHolder extends UniformHolder {
}
@Override
default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4f> value) {
default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4fc> value) {
location(name, UniformType.MAT4).ifPresent(id -> addUniform(updateFrequency, new MatrixUniform(id, value)));
return this;
@@ -2,6 +2,7 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
@@ -10,9 +11,9 @@ import java.util.function.Supplier;
public class MatrixUniform extends Uniform {
private final FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
private Matrix4f cachedValue;
private final Supplier<Matrix4f> value;
private final Supplier<Matrix4fc> value;
MatrixUniform(int location, Supplier<Matrix4f> value) {
MatrixUniform(int location, Supplier<Matrix4fc> value) {
super(location);
this.cachedValue = null;
@@ -21,7 +22,7 @@ public class MatrixUniform extends Uniform {
@Override
public void update() {
final Matrix4f newValue = value.get();
final Matrix4fc newValue = value.get();
if( newValue == null ){
throw new RuntimeException("MatrixUniform value is null");
}
@@ -1,12 +1,13 @@
package net.coderbot.iris.gl.uniform;
import net.minecraft.util.Vec3;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector2f;
import org.joml.Vector2i;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import org.joml.Vector4f;
import java.util.function.BooleanSupplier;
@@ -29,9 +30,9 @@ public interface UniformHolder {
UniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector2i> value);
UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3f> value);
UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3fc> value);
UniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3i> value);
UniformHolder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3ic> value);
UniformHolder uniformVanilla3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vec3> value);
@@ -43,7 +44,7 @@ public interface UniformHolder {
UniformHolder uniform4fArray(UniformUpdateFrequency updateFrequency, String name, Supplier<float[]> value);
UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4f> value);
UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4fc> value);
UniformHolder uniformMatrixFromArray(UniformUpdateFrequency updateFrequency, String name, Supplier<float[]> value);
@@ -3,21 +3,22 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import java.util.function.Supplier;
public class Vector3IntegerJomlUniform extends Uniform {
private Vector3i cachedValue;
private final Supplier<Vector3i> value;
private final Vector3i cachedValue;
private final Supplier<Vector3ic> value;
Vector3IntegerJomlUniform(int location, Supplier<Vector3i> value) {
Vector3IntegerJomlUniform(int location, Supplier<Vector3ic> value) {
this(location, value, null);
}
Vector3IntegerJomlUniform(int location, Supplier<Vector3i> value, ValueUpdateNotifier notifier) {
Vector3IntegerJomlUniform(int location, Supplier<Vector3ic> value, ValueUpdateNotifier notifier) {
super(location, notifier);
this.cachedValue = null;
this.cachedValue = new Vector3i();
this.value = value;
}
@@ -31,11 +32,11 @@ public class Vector3IntegerJomlUniform extends Uniform {
}
private void updateValue() {
Vector3i newValue = value.get();
Vector3ic newValue = value.get();
if (cachedValue == null || !newValue.equals(cachedValue)) {
cachedValue = newValue;
RenderSystem.uniform3i(this.location, newValue.x, newValue.y, newValue.z);
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y(), newValue.z());
RenderSystem.uniform3i(this.location, cachedValue.x(), cachedValue.y(), cachedValue.z());
}
}
}
@@ -3,15 +3,16 @@ package net.coderbot.iris.gl.uniform;
import com.gtnewhorizons.angelica.glsm.RenderSystem;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector4f;
import java.util.function.Supplier;
public class Vector3Uniform extends Uniform {
private final Vector3f cachedValue;
private final Supplier<Vector3f> value;
private final Supplier<Vector3fc> value;
Vector3Uniform(int location, Supplier<Vector3f> value) {
Vector3Uniform(int location, Supplier<Vector3fc> value) {
super(location);
this.cachedValue = new Vector3f();
@@ -44,7 +45,7 @@ public class Vector3Uniform extends Uniform {
@Override
public void update() {
Vector3f newValue = value.get();
Vector3fc newValue = value.get();
if (!newValue.equals(cachedValue)) {
cachedValue.set(newValue.x(), newValue.y(), newValue.z());
@@ -8,6 +8,7 @@ import net.coderbot.iris.shaderpack.option.OptionSet;
import net.coderbot.iris.shaderpack.option.Profile;
import net.coderbot.iris.shaderpack.option.ProfileSet;
import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement;
import net.coderbot.iris.shaderpack.option.menu.ProfileElementTracker;
import net.coderbot.iris.shaderpack.option.values.OptionValues;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
@@ -30,6 +31,7 @@ public class ProfileElementWidget extends BaseOptionElementWidget<OptionMenuProf
public void init(ShaderPackScreen screen, NavigationController navigation) {
super.init(screen, navigation);
this.setLabel(PROFILE_LABEL);
boolean secondProfileSet = ProfileElementTracker.isSecondProfileSet(this.element);
final ProfileSet profiles = this.element.profiles;
final OptionSet options = this.element.options;
@@ -41,7 +43,8 @@ public class ProfileElementWidget extends BaseOptionElementWidget<OptionMenuProf
this.previous = result.previous;
final Optional<String> profileName = result.current.map(p -> p.name);
this.profileLabel = profileName.map(name -> GuiUtil.translateOrDefault(name, "profile." + name)).orElse(PROFILE_CUSTOM);
String translationKey = "profile" + (secondProfileSet ? "2." : ".") + profileName.orElse("custom");
this.profileLabel = profileName.map(name -> GuiUtil.translateOrDefault(name, translationKey)).orElse(PROFILE_CUSTOM);
}
@Override
@@ -63,7 +66,7 @@ public class ProfileElementWidget extends BaseOptionElementWidget<OptionMenuProf
@Override
public String getCommentKey() {
return "profile.comment";
return ProfileElementTracker.isSecondProfileSet(this.element) ? "profile2.comment" : "profile.comment";
}
@Override
@@ -29,12 +29,14 @@ import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder;
import net.coderbot.iris.gl.buffer.ShaderStorageInfo;
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
import net.coderbot.iris.gl.image.GlImage;
import net.coderbot.iris.gl.image.ImageHolder;
import net.coderbot.iris.gl.image.ImageInformation;
import net.coderbot.iris.gl.program.ComputeProgram;
import net.coderbot.iris.gl.program.Program;
import net.coderbot.iris.gl.program.ProgramBuilder;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.sampler.SamplerHolder;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.gl.texture.DepthBufferFormat;
import net.coderbot.iris.gl.texture.TextureType;
@@ -45,6 +47,7 @@ import net.coderbot.iris.postprocess.BufferFlipper;
import net.coderbot.iris.postprocess.CenterDepthSampler;
import net.coderbot.iris.postprocess.CompositeRenderer;
import net.coderbot.iris.postprocess.FinalPassRenderer;
import net.coderbot.iris.postprocess.FullScreenQuadRenderer;
import net.coderbot.iris.postprocess.ProgramBuildContext;
import net.coderbot.iris.rendertarget.IRenderTargetExt;
import net.coderbot.iris.rendertarget.NativeImageBackedSingleColorTexture;
@@ -176,6 +179,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
private final boolean oldLighting;
private final boolean allowConcurrentCompute;
private final OptionalInt forcedShadowRenderDistanceChunks;
private final CloudSetting dhCloudSetting;
private Pass current = null;
@@ -191,6 +195,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
private int currentSpecularTexture;
private PackDirectives packDirectives;
private final Set<FeatureFlags> activeFeatures;
private final ProgramFallbackResolver resolver;
public DeferredWorldRenderingPipeline(ProgramSet programs) {
Objects.requireNonNull(programs);
@@ -205,7 +210,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
.map(DeferredWorldRenderingPipeline::submitCompositeTransform)
.orElse(null);
final ProgramFallbackResolver resolver = new ProgramFallbackResolver(programs);
resolver = new ProgramFallbackResolver(programs);
final Map<Pair<String, InputAvailability>, CompletableFuture<Map<PatchShaderType, String>>> attributeTransformFutures = submitAttributeTransforms(resolver);
final Optional<ProgramSource> terrainSource = first(programs.getGbuffersTerrain(), programs.getGbuffersTexturedLit(), programs.getGbuffersTextured(), programs.getGbuffersBasic());
@@ -227,6 +232,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
this.shouldRenderWeather = programs.getPackDirectives().shouldRenderWeather();
this.shouldRenderWeatherParticles = programs.getPackDirectives().shouldRenderWeatherParticles();
this.shouldWriteRainAndSnowToDepthBuffer = programs.getPackDirectives().rainDepth();
this.dhCloudSetting = programs.getPackDirectives().getDHCloudSetting();
this.shouldRenderParticlesBeforeDeferred = programs.getPackDirectives().getParticleRenderingSettings()
.map(s -> s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.BEFORE || s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.MIXED)
.orElse(false);
@@ -367,6 +373,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
null, ProgramId.Clouds, ProgramId.Clouds,
null, ProgramId.DamagedBlock, ProgramId.DamagedBlock,
ProgramId.Block, ProgramId.Block, ProgramId.Block,
ProgramId.BlockTrans, ProgramId.BlockTrans, ProgramId.BlockTrans,
ProgramId.BeaconBeam, ProgramId.BeaconBeam, ProgramId.BeaconBeam,
ProgramId.Entities, ProgramId.Entities, ProgramId.Entities,
ProgramId.EntitiesTrans, ProgramId.EntitiesTrans, ProgramId.EntitiesTrans,
@@ -585,7 +592,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
renderTargets, flippedAfterPrepare, flippedAfterTranslucent,
celeritasShadowFb);
this.dhCompat = new DHCompat();
this.dhCompat = new DHCompat(this, shadowDirectives.isDhShadowEnabled().orElse(true));
}
private RenderTargets getRenderTargets() {
@@ -719,6 +726,10 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
return RenderCondition.ENTITIES;
}
case BLOCK_ENTITIES:
if (GLStateManager.getBlendState().getSrcRgb() == SRC_ALPHA &&
GLStateManager.getBlendState().getDstRgb() == ONE_MINUS_SRC_ALPHA) {
return RenderCondition.BLOCK_ENTITIES_TRANSLUCENT;
}
return RenderCondition.BLOCK_ENTITIES;
case DESTROY:
return RenderCondition.DESTROY;
@@ -749,6 +760,13 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
return p != null ? p.getProgramId() : -1;
}
/**
* Called when a mod overrides the GL program away from the active Iris pass
*/
public void onModProgramOverride() {
current = null;
}
private void matchPass() {
if (!isRenderingWorld || isRenderingFullScreenPass || isPostChain || !isMainBound) {
return;
@@ -883,7 +901,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
builder.bindAttributeLocation(13, "at_tangent");
builder.bindAttributeLocation(14, "at_midBlock");
AlphaTestOverride alphaTestOverride = programDirectives.getAlphaTestOverride().orElse(null);
AlphaTestOverride alphaTestOverride = programDirectives.getAlphaTestOverride()
.orElse(id.getDefaultAlphaTestOverride());
List<BufferBlendOverride> bufferOverrides = new ArrayList<>();
@@ -902,6 +921,38 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
return pass;
}
public void addGbufferOrShadowSamplers(SamplerHolder samplers, ImageHolder images, Supplier<ImmutableSet<Integer>> flipped,
boolean isShadowPass, boolean hasTexture, boolean hasLightmap, boolean hasOverlay) {
TextureStage textureStage = TextureStage.GBUFFERS_AND_SHADOW;
ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor =
ProgramSamplers.customTextureSamplerInterceptor(samplers, customTextureManager.getCustomTextureIdMap(textureStage));
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false, this);
IrisImages.addRenderTargetImages(images, flipped, renderTargets);
if (!shouldBindPBR) {
shouldBindPBR = IrisSamplers.hasPBRSamplers(customTextureSamplerInterceptor);
}
IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(hasTexture, hasLightmap));
if (!isShadowPass) {
IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets);
}
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture());
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures());
IrisImages.addCustomImages(images, customImages);
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, true);
}
if (isShadowPass || IrisImages.hasShadowImages(images)) {
IrisImages.addShadowColorImages(images, shadowTargetsSupplier.get(), null);
}
}
private boolean isPostChain;
private boolean isMainBound = true;
@@ -933,6 +984,56 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
}
}
public CloudSetting getDHCloudSetting() {
return dhCloudSetting;
}
public Optional<ProgramSource> getDHTerrainShader() {
return resolver.resolve(ProgramId.DhTerrain);
}
public Optional<ProgramSource> getDHGenericShader() {
return resolver.resolve(ProgramId.DhGeneric);
}
public Optional<ProgramSource> getDHWaterShader() {
return resolver.resolve(ProgramId.DhWater);
}
public Optional<ProgramSource> getDHShadowShader() {
return resolver.resolve(ProgramId.DhShadow);
}
public CustomUniforms getCustomUniforms() {
return customUniforms;
}
public GlFramebuffer createDHFramebuffer(ProgramSource sources, boolean trans) {
return renderTargets.createDHFramebuffer(trans ? flippedAfterTranslucent : flippedAfterPrepare,
sources.getDirectives().getDrawBuffers());
}
public ImmutableSet<Integer> getFlippedBeforeShadow() {
return flippedBeforeShadow;
}
public ImmutableSet<Integer> getFlippedAfterPrepare() {
return flippedAfterPrepare;
}
public ImmutableSet<Integer> getFlippedAfterTranslucent() {
return flippedAfterTranslucent;
}
public GlFramebuffer createDHFramebufferShadow(ProgramSource sources) {
return shadowRenderTargets.createDHFramebuffer(ImmutableSet.of(), new int[]{0, 1});
}
public boolean hasShadowRenderTargets() {
return shadowRenderTargets != null;
}
private final class Pass {
@Nullable
private final Program program;
@@ -973,12 +1074,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
GLStateManager.glViewport(0, 0, main.framebufferWidth, main.framebufferHeight);
}
if (program != null) {
program.use();
}
DeferredWorldRenderingPipeline.this.customUniforms.push(this);
// Apply state overrides before program.use() so that uniforms (e.g. iris_currentAlphaTest)
// read the correct GLSM state during upload, not the stale vanilla state.
if (alphaTestOverride != null) {
alphaTestOverride.apply();
} else {
@@ -996,6 +1093,12 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
if (bufferBlendOverrides != null && !bufferBlendOverrides.isEmpty()) {
bufferBlendOverrides.forEach(BufferBlendOverride::apply);
}
if (program != null) {
program.use();
}
DeferredWorldRenderingPipeline.this.customUniforms.push(this);
}
public void stopUsing() {
@@ -1028,6 +1131,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
BlendModeOverride.restore();
AlphaTestOverride.restore();
FullScreenQuadRenderer.clearLocCache();
destroyPasses(table);
// Destroy the composite rendering pipeline
@@ -1077,6 +1181,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
// While it's possible to just clear them instead and reuse them, we'd need to investigate whether or not this
// would help performance.
renderTargets.destroy();
dhCompat.clearPipeline();
// destroy the shadow render targets
if (shadowRenderTargets != null) {
@@ -130,7 +130,7 @@ public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeli
return new FrameUpdateNotifier();
}
private static final DHCompat DH_COMPAT = new DHCompat();
private static final DHCompat DH_COMPAT = new DHCompat(null, false);
@Override
public DHCompat getDHCompat() {
@@ -39,6 +39,9 @@ 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()) {
return;
}
if (prettyPrintShaders) {
final Path debugOutDir = Minecraft.getMinecraft().mcDataDir.toPath().resolve("patched_shaders");
if (!outputLocationCleared) {
@@ -10,6 +10,7 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
import net.coderbot.iris.Iris;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.gui.option.IrisVideoSettings;
import net.coderbot.iris.layer.GbufferPrograms;
import net.coderbot.iris.shaderpack.PackDirectives;
@@ -43,6 +44,7 @@ import net.minecraft.profiler.Profiler;
import net.minecraft.tileentity.TileEntity;
import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
@@ -68,6 +70,8 @@ public class ShadowRenderer {
public static final List<TileEntity> globalTileEntities = new ArrayList<>();
public static boolean ACTIVE = false;
public static Frustrum FRUSTUM;
private static final Comparator<Entity> ENTITY_CLASS_COMPARATOR = Comparator.comparingInt(a -> System.identityHashCode(a.getClass()));
private static final NonCullingFrustum NON_CULLING_FRUSTUM = new NonCullingFrustum();
private static final CullEverythingFrustum CULL_EVERYTHING_FRUSTUM = new CullEverythingFrustum();
@@ -111,12 +115,16 @@ public class ShadowRenderer {
private double lastBoxCullerDistance = -1;
private double lastAdvancedBoxCullerDistance = -1;
private double lastTileEntityCullerDistance = -1;
private final boolean shouldRenderDH;
private final float nearPlane, farPlane;
public ShadowRenderer(ProgramSource shadow, PackDirectives directives, ShadowRenderTargets shadowRenderTargets, ShadowCompositeRenderer compositeRenderer) {
this.profiler = Minecraft.getMinecraft().mcProfiler;
final PackShadowDirectives shadowDirectives = directives.getShadowDirectives();
this.nearPlane = shadowDirectives.getNearPlane();
this.farPlane = shadowDirectives.getFarPlane();
this.halfPlaneLength = shadowDirectives.getDistance();
this.voxelDistance = shadowDirectives.getVoxelDistance();
@@ -129,6 +137,7 @@ public class ShadowRenderer {
this.shouldRenderEntities = shadowDirectives.shouldRenderEntities();
this.shouldRenderPlayer = shadowDirectives.shouldRenderPlayer();
this.shouldRenderBlockEntities = shadowDirectives.shouldRenderBlockEntities();
this.shouldRenderDH = shadowDirectives.isDhShadowEnabled().orElse(false);
this.compositeRenderer = compositeRenderer;
@@ -348,14 +357,16 @@ public class ShadowRenderer {
shadowLightVectorCache.set(shadowLightPosition.x(), shadowLightPosition.y(), shadowLightPosition.z());
shadowLightVectorCache.normalize();
Matrix4fc projView = ((shouldRenderDH && DHCompat.hasRenderingEnabled()) ? DHCompat.getProjection() : RenderingState.INSTANCE.getProjectionMatrix());
if (hasSafeZone) {
BoxCuller distanceCuller = new BoxCuller(halfPlaneLength * renderMultiplier);
SafeZoneCullingFrustum safeZoneFrustum = new SafeZoneCullingFrustum(
RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(),
RenderingState.INSTANCE.getModelViewMatrix(), projView,
shadowLightVectorCache, boxCuller, distanceCuller);
return holder.setInfo(safeZoneFrustum, distanceInfo, cullingInfo);
} else {
cachedAdvancedFrustum.init(RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(), shadowLightVectorCache, boxCuller);
cachedAdvancedFrustum.init(RenderingState.INSTANCE.getModelViewMatrix(), projView, shadowLightVectorCache, boxCuller);
return holder.setInfo(cachedAdvancedFrustum, distanceInfo, cullingInfo);
}
}
@@ -630,12 +641,12 @@ public class ShadowRenderer {
final MatrixStack modelView = getShadowModelView();
MODELVIEW.set(modelView.peek().getModel());
final Matrix4f shadowProjection;
final Matrix4f shadowProjection;
if (this.fov != null) {
// If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs)
shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov);
shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov);
} else {
shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength);
shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength, nearPlane < 0 ? -DHCompat.getRenderDistance() : nearPlane, farPlane < 0 ? DHCompat.getRenderDistance() : farPlane);
}
PROJECTION.set(shadowProjection);
@@ -649,6 +660,7 @@ public class ShadowRenderer {
profiler.startSection("initialize frustum");
terrainFrustumHolder = createShadowFrustum(renderDistanceMultiplier, terrainFrustumHolder);
FRUSTUM = terrainFrustumHolder.getFrustum();
// Use the player/entity position for shadow rendering
final Vector3d entityPos = playerCamera.getEntityPos();
@@ -21,6 +21,7 @@ class CoreTransformHelper {
transformer.injectVariable("uniform mat4 iris_ProjectionMatrixInverse;");
transformer.injectVariable("uniform mat3 iris_NormalMatrix;");
transformer.injectVariable("uniform mat4 iris_LightmapTextureMatrix;");
transformer.injectVariable("uniform mat4 iris_TextureMatrix;");
final Map<String, String> renames = new HashMap<>();
renames.put("gl_ModelViewMatrix", "iris_ModelViewMatrix");
@@ -32,12 +33,12 @@ class CoreTransformHelper {
final Map<String, String> replacements = new HashMap<>();
replacements.put("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)");
replacements.put("gl_TextureMatrix[0]", "mat4(1.0)");
replacements.put("gl_TextureMatrix[0]", "iris_TextureMatrix");
replacements.put("gl_TextureMatrix[1]", "iris_LightmapTextureMatrix");
replacements.forEach(transformer::replaceExpression);
// Catch any remaining gl_TextureMatrix references (e.g. [2]-[7])
transformer.replaceExpression("gl_TextureMatrix", "mat4[8](mat4(1.0), iris_LightmapTextureMatrix, mat4(1.0), mat4(1.0), mat4(1.0), mat4(1.0), mat4(1.0), mat4(1.0))");
transformer.replaceExpression("gl_TextureMatrix", "mat4[8](iris_TextureMatrix, iris_LightmapTextureMatrix, mat4(1.0), mat4(1.0), mat4(1.0), mat4(1.0), mat4(1.0), mat4(1.0))");
}
/**
@@ -0,0 +1,114 @@
package net.coderbot.iris.pipeline.transform;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import org.taumc.glsl.Transformer;
public class DHGenericTransformer {
public static void transform(Transformer transformer, Parameters parameters, int glslVersion) {
CommonTransformer.transform(transformer, parameters, true, glslVersion);
transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)");
transformer.replaceExpression("gl_TextureMatrix[1]", "mat4(1.0)");
transformer.rename("gl_ProjectionMatrix", "iris_ProjectionMatrix");
if (parameters.type == ShaderType.VERTEX) {
// Alias of gl_MultiTexCoord1 on 1.15+ for OptiFine
// See https://github.com/IrisShaders/Iris/issues/1149
transformer.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1");
transformer.replaceExpression("gl_MultiTexCoord0", "vec4(0.0, 0.0, 0.0, 1.0)");
transformer.replaceExpression("gl_MultiTexCoord1", "vec4(_vert_tex_light_coord, 0.0, 1.0)");
replaceGlMultiTexCoordBounded(transformer, 4, 7);
}
transformer.rename("gl_Color", "_vert_color");
if (parameters.type == ShaderType.VERTEX) {
transformer.replaceExpression("gl_Normal", "_vert_normal");
}
transformer.replaceExpression("gl_NormalMatrix", "iris_NormalMatrix");
addIfNotExists(transformer, "iris_NormalMatrix", "uniform mat3 iris_NormalMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrixInverse", "uniform mat4 iris_ModelViewMatrixInverse;");
addIfNotExists(transformer, "iris_ProjectionMatrixInverse", "uniform mat4 iris_ProjectionMatrixInverse;");
transformer.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix");
transformer.rename("gl_ModelViewMatrixInverse", "iris_ModelViewMatrixInverse");
transformer.rename("gl_ProjectionMatrixInverse", "iris_ProjectionMatrixInverse");
if (parameters.type == ShaderType.VERTEX) {
if (transformer.containsCall("ftransform")) {
transformer.injectFunction("vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }");
}
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
transformer.injectFunction("vec4 getVertexPosition() { return vec4(_vert_position, 1.0); }");
transformer.replaceExpression("gl_Vertex", "getVertexPosition()");
injectVertInit(transformer);
} else {
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
}
transformer.replaceExpression("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)");
ShaderTransformer.applyIntelHd4000Workaround(transformer);
}
public static void injectVertInit(Transformer transformer) {
addIfNotExists(transformer, "_vert_position", "vec3 _vert_position;");
addIfNotExists(transformer, "_vert_tex_light_coord", "vec2 _vert_tex_light_coord;");
addIfNotExists(transformer, "dhMaterialId", "int dhMaterialId;");
addIfNotExists(transformer, "_vert_color", "vec4 _vert_color;");
addIfNotExists(transformer, "_vert_normal", "vec3 _vert_normal;");
addIfNotExists(transformer, "uOffsetChunk", "uniform ivec3 uOffsetChunk;");
addIfNotExists(transformer, "uOffsetSubChunk", "uniform vec3 uOffsetSubChunk;");
addIfNotExists(transformer, "uCameraPosChunk", "uniform ivec3 uCameraPosChunk;");
addIfNotExists(transformer, "uCameraPosSubChunk", "uniform vec3 uCameraPosSubChunk;");
addIfNotExists(transformer, "uSkyLight", "uniform int uSkyLight;");
addIfNotExists(transformer, "uBlockLight", "uniform int uBlockLight;");
addIfNotExists(transformer, "iris_color", "in vec4 iris_color;");
addIfNotExists(transformer, "aScale", "in vec3 aScale;");
addIfNotExists(transformer, "aTranslateChunk", "in ivec3 aTranslateChunk;");
addIfNotExists(transformer, "aTranslateSubChunk", "in vec3 aTranslateSubChunk;");
addIfNotExists(transformer, "aMaterial", "in int aMaterial;");
addIfNotExists(transformer, "vPosition", "in vec3 vPosition;");
transformer.injectFunction("const vec3 irisNormals[6] = vec3[](vec3(0,0,-1), vec3(0,0,1), vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0));");
transformer.injectFunction(
"void _vert_init() {"
+ " vec3 trans = vec3(aTranslateChunk + uOffsetChunk - uCameraPosChunk) * 16.0;"
+ " trans += (aTranslateSubChunk + uOffsetSubChunk - uCameraPosSubChunk);"
+ " mat4 transform = mat4("
+ " aScale.x, 0.0, 0.0, 0.0,"
+ " 0.0, aScale.y, 0.0, 0.0,"
+ " 0.0, 0.0, aScale.z, 0.0,"
+ " trans.x, trans.y, trans.z, 1.0"
+ " );"
+ " _vert_position = (transform * vec4(vPosition, 1.0)).xyz;"
+ " _vert_normal = irisNormals[int(floor(float(gl_VertexID) / 4.0))];"
+ " float blockLight = (float(uBlockLight) + 0.5) / 16.0;"
+ " float skyLight = (float(uSkyLight) + 0.5) / 16.0;"
+ " _vert_tex_light_coord = vec2(blockLight, skyLight);"
+ " dhMaterialId = aMaterial;"
+ " _vert_color = iris_color;"
+ " }"
);
transformer.prependMain("_vert_init();");
}
private static void addIfNotExists(Transformer transformer, String name, String code) {
if (!transformer.hasVariable(name)) {
transformer.injectVariable(code);
}
}
private static void replaceGlMultiTexCoordBounded(Transformer transformer, int from, int to) {
for (int i = from; i <= to; i++) {
transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)");
}
}
}
@@ -0,0 +1,106 @@
package net.coderbot.iris.pipeline.transform;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import org.taumc.glsl.Transformer;
public class DHTerrainTransformer {
public static void transform(Transformer transformer, Parameters parameters, int glslVersion) {
CommonTransformer.transform(transformer, parameters, true, glslVersion);
transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)");
transformer.replaceExpression("gl_TextureMatrix[1]", "mat4(1.0)");
transformer.rename("gl_ProjectionMatrix", "iris_ProjectionMatrix");
if (parameters.type == ShaderType.VERTEX) {
// Alias of gl_MultiTexCoord1 on 1.15+ for OptiFine
// See https://github.com/IrisShaders/Iris/issues/1149
transformer.rename("gl_MultiTexCoord2", "gl_MultiTexCoord1");
transformer.replaceExpression("gl_MultiTexCoord0", "vec4(0.0, 0.0, 0.0, 1.0)");
transformer.replaceExpression("gl_MultiTexCoord1", "vec4(_vert_tex_light_coord, 0.0, 1.0)");
replaceGlMultiTexCoordBounded(transformer, 4, 7);
}
transformer.rename("gl_Color", "_vert_color");
if (parameters.type == ShaderType.VERTEX) {
transformer.replaceExpression("gl_Normal", "_vert_normal");
}
transformer.replaceExpression("gl_NormalMatrix", "iris_NormalMatrix");
addIfNotExists(transformer, "iris_NormalMatrix", "uniform mat3 iris_NormalMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrixInverse", "uniform mat4 iris_ModelViewMatrixInverse;");
addIfNotExists(transformer, "iris_ProjectionMatrixInverse", "uniform mat4 iris_ProjectionMatrixInverse;");
transformer.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix");
transformer.rename("gl_ModelViewMatrixInverse", "iris_ModelViewMatrixInverse");
transformer.rename("gl_ProjectionMatrixInverse", "iris_ProjectionMatrixInverse");
if (parameters.type == ShaderType.VERTEX) {
if (transformer.containsCall("ftransform")) {
transformer.injectFunction("vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }");
}
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
transformer.injectFunction("vec4 getVertexPosition() { return vec4(modelOffset + _vert_position, 1.0); }");
transformer.replaceExpression("gl_Vertex", "getVertexPosition()");
injectVertInit(transformer);
} else {
addIfNotExists(transformer, "iris_ModelViewMatrix", "uniform mat4 iris_ModelViewMatrix;");
addIfNotExists(transformer, "iris_ProjectionMatrix", "uniform mat4 iris_ProjectionMatrix;");
}
transformer.replaceExpression("gl_ModelViewProjectionMatrix", "(iris_ProjectionMatrix * iris_ModelViewMatrix)");
ShaderTransformer.applyIntelHd4000Workaround(transformer);
}
public static void injectVertInit(Transformer transformer) {
addIfNotExists(transformer, "_vert_position", "vec3 _vert_position;");
addIfNotExists(transformer, "_vert_tex_light_coord", "vec2 _vert_tex_light_coord;");
addIfNotExists(transformer, "dhMaterialId", "int dhMaterialId;");
addIfNotExists(transformer, "_vert_color", "vec4 _vert_color;");
addIfNotExists(transformer, "_vert_normal", "vec3 _vert_normal;");
addIfNotExists(transformer, "mircoOffset", "uniform float mircoOffset;");
addIfNotExists(transformer, "modelOffset", "uniform vec3 modelOffset;");
addIfNotExists(transformer, "iris_color", "in vec4 iris_color;");
addIfNotExists(transformer, "vPosition", "in uvec4 vPosition;");
addIfNotExists(transformer, "irisExtra", "in uvec4 irisExtra;");
transformer.injectFunction("const vec3 irisNormals[6] = vec3[](vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1), vec3(-1,0,0), vec3(1,0,0));");
transformer.injectFunction(
"void _vert_init() {"
+ " uint meta = vPosition.a;"
+ " uint mirco = (meta & 0xFF00u) >> 8u;"
+ " float mx = (mirco & 1u) != 0u ? mircoOffset : 0.0;"
+ " mx = (mirco & 2u) != 0u ? -mx : mx;"
+ " float my = (mirco & 4u) != 0u ? mircoOffset : 0.0;"
+ " my = (mirco & 8u) != 0u ? -my : my;"
+ " float mz = (mirco & 16u) != 0u ? mircoOffset : 0.0;"
+ " mz = (mirco & 32u) != 0u ? -mz : mz;"
+ " uint lights = meta & 0xFFu;"
+ " _vert_position = (vPosition.xyz + vec3(mx, my, mz));"
+ " _vert_normal = irisNormals[int(irisExtra.y)];"
+ " dhMaterialId = int(irisExtra.x);"
+ " _vert_tex_light_coord = vec2((float(lights / 16u) + 0.5) / 16.0, (mod(float(lights), 16.0) + 0.5) / 16.0);"
+ " _vert_color = iris_color;"
+ " }"
);
transformer.prependMain("_vert_init();");
}
private static void addIfNotExists(Transformer transformer, String name, String code) {
if (!transformer.hasVariable(name)) {
transformer.injectVariable(code);
}
}
private static void replaceGlMultiTexCoordBounded(Transformer transformer, int from, int to) {
for (int i = from; i <= to; i++) {
transformer.replaceExpression("gl_MultiTexCoord" + i, "vec4(0.0, 0.0, 0.0, 1.0)");
}
}
}
@@ -4,5 +4,7 @@ public enum Patch {
ATTRIBUTES,
CELERITAS_TERRAIN,
COMPOSITE,
COMPUTE
COMPUTE,
DH_TERRAIN,
DH_GENERIC
}
@@ -439,6 +439,12 @@ public class ShaderTransformer {
case COMPUTE:
ComputeTransformer.transform(transformer, parameters, versionInt);
break;
case DH_TERRAIN:
DHTerrainTransformer.transform(transformer, parameters, versionInt);
break;
case DH_GENERIC:
DHGenericTransformer.transform(transformer, parameters, versionInt);
break;
default:
throw new IllegalStateException("Unknown patch type: " + patchType.name());
}
@@ -7,6 +7,7 @@ import net.coderbot.iris.helpers.Tri;
import net.coderbot.iris.pipeline.transform.parameter.AttributeParameters;
import net.coderbot.iris.pipeline.transform.parameter.CeleritasTerrainParameters;
import net.coderbot.iris.pipeline.transform.parameter.ComputeParameters;
import net.coderbot.iris.pipeline.transform.parameter.DHParameters;
import net.coderbot.iris.pipeline.transform.parameter.Parameters;
import net.coderbot.iris.pipeline.transform.parameter.TextureStageParameters;
import net.coderbot.iris.shaderpack.texture.TextureStage;
@@ -127,6 +128,23 @@ public class TransformPatcher {
return transform(vertex, geometry, tessControl, tessEval, fragment, new TextureStageParameters(Patch.COMPOSITE, stage, textureMap));
}
public static Map<PatchShaderType, String> patchDHTerrain(
String name, String vertex, String tessControl, String tessEval, String geometry, String fragment,
Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return transform(vertex, geometry, tessControl, tessEval, fragment,
new DHParameters(Patch.DH_TERRAIN, textureMap));
}
public static Map<PatchShaderType, String> patchDHGeneric(
String name, String vertex, String tessControl, String tessEval, String geometry, String fragment,
Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return transform(vertex, geometry, tessControl, tessEval, fragment,
new DHParameters(Patch.DH_GENERIC, textureMap));
}
public static Map<PatchShaderType, String> patchComposite(String vertex, String geometry, String fragment, TextureStage stage, Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
return patchComposite(vertex, geometry, null, null, fragment, stage, textureMap);
}
@@ -0,0 +1,18 @@
package net.coderbot.iris.pipeline.transform.parameter;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import net.coderbot.iris.gl.texture.TextureType;
import net.coderbot.iris.helpers.Tri;
import net.coderbot.iris.pipeline.transform.Patch;
import net.coderbot.iris.shaderpack.texture.TextureStage;
public class DHParameters extends Parameters {
public DHParameters(Patch patch, Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap) {
super(patch, textureMap);
}
@Override
public TextureStage getTextureStage() {
return TextureStage.GBUFFERS_AND_SHADOW;
}
}
@@ -78,6 +78,11 @@ public class FullScreenQuadRenderer {
/** Per-program cached uniform locations: [mvLoc, projLoc]. Populated on first miss. */
private static final Int2ObjectOpenHashMap<int[]> compositeLocCache = new Int2ObjectOpenHashMap<>();
/** Clear cached uniform locations. Must be called when composite programs are destroyed (e.g. shader reload). */
public static void clearLocCache() {
compositeLocCache.clear();
}
public static void uploadCompositeMatrices() {
final int program = GLStateManager.glGetInteger(GL20.GL_CURRENT_PROGRAM);
if (program == 0) return;
@@ -248,6 +248,16 @@ public class RenderTargets {
return framebuffer;
}
public GlFramebuffer createDHFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
}
ImmutableSet<Integer> stageWritesToMain = invert(stageWritesToAlt, drawBuffers);
return createColorFramebuffer(stageWritesToMain, drawBuffers);
}
public GlFramebuffer createGbufferFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
@@ -28,7 +28,7 @@ public class PackDirectives {
@Getter private float eyeBrightnessHalfLife;
@Getter private float centerDepthHalfLife;
@Getter private CloudSetting cloudSetting;
@Getter private CloudSetting dhCloudSetting;
private CloudSetting dhCloudSetting;
private boolean underwaterOverlay;
private boolean vignette;
private boolean sun;
@@ -181,6 +181,10 @@ public class PackDirectives {
return concurrentCompute;
}
public CloudSetting getDHCloudSetting() {
return dhCloudSetting;
}
private static float clamp(float val, float lo, float hi) {
return Math.max(lo, Math.min(hi, val));
}
@@ -30,6 +30,8 @@ public class PackShadowDirectives {
private final boolean shouldRenderPlayer;
private final boolean shouldRenderBlockEntities;
@Getter private final ShadowCullState cullingState;
private final OptionalBoolean dhShadowEnabled;
private float nearPlane, farPlane;
private final ImmutableList<DepthSamplingSettings> depthSamplingSettings;
private final ImmutableList<SamplingSettings> colorSamplingSettings;
@@ -53,6 +55,8 @@ public class PackShadowDirectives {
// shadowRenderDistanceMul to a nonzero value, since having a high shadow render distance will impact
// performance quite heavily on most systems.
this.distance = 160.0f;
this.nearPlane = 0.05f;
this.farPlane = 256.0f;
this.voxelDistance = 0.0f;
// By default, shadows are not culled based on distance from the player. However, pack authors may
@@ -81,6 +85,7 @@ public class PackShadowDirectives {
this.shouldRenderBlockEntities = properties.getShadowBlockEntities().orElse(true);
this.cullingState = properties.getShadowCulling();
this.shadowEnabled = properties.getShadowEnabled();
this.dhShadowEnabled = properties.getDhShadowEnabled();
this.depthSamplingSettings = ImmutableList.of(new DepthSamplingSettings(), new DepthSamplingSettings());
@@ -97,6 +102,8 @@ public class PackShadowDirectives {
this.resolution = shadowDirectives.resolution;
this.fov = shadowDirectives.fov;
this.distance = shadowDirectives.distance;
this.nearPlane = shadowDirectives.nearPlane;
this.farPlane = shadowDirectives.farPlane;
this.voxelDistance = shadowDirectives.voxelDistance;
this.distanceRenderMul = shadowDirectives.distanceRenderMul;
this.entityShadowDistanceMul = shadowDirectives.entityShadowDistanceMul;
@@ -111,6 +118,7 @@ public class PackShadowDirectives {
this.depthSamplingSettings = shadowDirectives.depthSamplingSettings;
this.colorSamplingSettings = shadowDirectives.colorSamplingSettings;
this.shadowEnabled = shadowDirectives.shadowEnabled;
this.dhShadowEnabled = shadowDirectives.dhShadowEnabled;
}
public int getResolution() {
@@ -125,6 +133,18 @@ public class PackShadowDirectives {
return distance;
}
public float getNearPlane() {
return nearPlane;
}
public float getFarPlane() {
return farPlane;
}
public OptionalBoolean isDhShadowEnabled() {
return dhShadowEnabled;
}
public float getVoxelDistance() {
return voxelDistance;
}
@@ -186,7 +206,8 @@ public class PackShadowDirectives {
directives.acceptCommentFloatDirective("SHADOWHPL", distance -> this.distance = distance);
directives.acceptConstFloatDirective("shadowDistance", distance -> this.distance = distance);
directives.acceptConstFloatDirective("shadowNearPlane", nearPlane -> this.nearPlane = nearPlane);
directives.acceptConstFloatDirective("shadowFarPlane", farPlane -> this.farPlane = farPlane);
directives.acceptConstFloatDirective("entityShadowDistanceMul", distance -> this.entityShadowDistanceMul = distance);
directives.acceptConstFloatDirective("shadowDistanceRenderMul", distanceRenderMul -> {
@@ -43,6 +43,7 @@ public class ProgramSet {
private final ProgramSource gbuffersGlint;
private final ProgramSource gbuffersEntityEyes;
private final ProgramSource gbuffersBlock;
private final ProgramSource gbuffersBlockTrans;
private final ProgramSource gbuffersHand;
private final ProgramSource[] deferred;
@@ -55,7 +56,10 @@ public class ProgramSet {
private final ComputeSource[][] compositeCompute;
private final ProgramSource compositeFinal;
private final ComputeSource[] finalCompute;
private final ProgramSource dhTerrain;
private final ProgramSource dhGeneric;
private final ProgramSource dhWater;
private final ProgramSource dhShadow;
private final ShaderPack pack;
@@ -116,7 +120,12 @@ public class ProgramSet {
this.gbuffersGlint = readProgramSource(directory, sourceProvider, "gbuffers_armor_glint", this, shaderProperties);
this.gbuffersEntityEyes = readProgramSource(directory, sourceProvider, "gbuffers_spidereyes", this, shaderProperties);
this.gbuffersBlock = readProgramSource(directory, sourceProvider, "gbuffers_block", this, shaderProperties);
this.gbuffersBlockTrans = readProgramSource(directory, sourceProvider, "gbuffers_block_translucent", this, shaderProperties);
this.gbuffersHand = readProgramSource(directory, sourceProvider, "gbuffers_hand", this, shaderProperties);
this.dhTerrain = readProgramSource(directory, sourceProvider, "dh_terrain", this, shaderProperties);
this.dhGeneric = readProgramSource(directory, sourceProvider, "dh_generic", this, shaderProperties);
this.dhWater = readProgramSource(directory, sourceProvider, "dh_water", this, shaderProperties);
this.dhShadow = readProgramSource(directory, sourceProvider, "dh_shadow", this, shaderProperties);
this.deferred = readProgramArray(directory, sourceProvider, "deferred", shaderProperties);
this.deferredCompute = new ComputeSource[deferred.length][];
@@ -216,8 +225,8 @@ public class ProgramSet {
programs.addAll (Arrays.asList(
gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain,
gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather,
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock,
gbuffersHand
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans,
gbuffersHand, dhShadow, dhTerrain, dhGeneric, dhWater
));
for (ComputeSource[] computeSources : compositeCompute) {
@@ -377,36 +386,61 @@ public class ProgramSet {
return gbuffersBlock.requireValid();
}
public Optional<ProgramSource> getGbuffersBlockTrans() {
return gbuffersBlockTrans.requireValid();
}
public Optional<ProgramSource> getGbuffersHand() {
return gbuffersHand.requireValid();
}
public Optional<ProgramSource> getDhTerrain() {
return dhTerrain.requireValid();
}
public Optional<ProgramSource> getDhGeneric() {
return dhGeneric.requireValid();
}
public Optional<ProgramSource> getDhWater() {
return dhWater.requireValid();
}
public Optional<ProgramSource> getDhShadow() {
return dhShadow.requireValid();
}
public Optional<ProgramSource> get(ProgramId programId) {
return switch (programId) {
case Shadow -> getShadow();
case Basic -> getGbuffersBasic();
case Line -> gbuffersLine.requireValid();
case Textured -> getGbuffersTextured();
case TexturedLit -> getGbuffersTexturedLit();
case SkyBasic -> getGbuffersSkyBasic();
case SkyTextured -> getGbuffersSkyTextured();
case Clouds -> getGbuffersClouds();
case Terrain -> getGbuffersTerrain();
case DamagedBlock -> getGbuffersDamagedBlock();
case Block -> getGbuffersBlock();
case BeaconBeam -> getGbuffersBeaconBeam();
case Entities -> getGbuffersEntities();
case EntitiesTrans -> getGbuffersEntitiesTrans();
case EntitiesGlowing -> getGbuffersEntitiesGlowing();
case ArmorGlint -> getGbuffersGlint();
case SpiderEyes -> getGbuffersEntityEyes();
case Hand -> getGbuffersHand();
case Weather -> getGbuffersWeather();
case Water -> getGbuffersWater();
case HandWater -> getGbuffersHandWater();
case Final -> getCompositeFinal();
default -> Optional.empty();
};
return switch (programId) {
case Shadow -> getShadow();
case Basic -> getGbuffersBasic();
case Line -> gbuffersLine.requireValid();
case Textured -> getGbuffersTextured();
case TexturedLit -> getGbuffersTexturedLit();
case SkyBasic -> getGbuffersSkyBasic();
case SkyTextured -> getGbuffersSkyTextured();
case Clouds -> getGbuffersClouds();
case Terrain -> getGbuffersTerrain();
case DamagedBlock -> getGbuffersDamagedBlock();
case Block -> getGbuffersBlock();
case BlockTrans -> getGbuffersBlockTrans();
case BeaconBeam -> getGbuffersBeaconBeam();
case Entities -> getGbuffersEntities();
case EntitiesTrans -> getGbuffersEntitiesTrans();
case EntitiesGlowing -> getGbuffersEntitiesGlowing();
case ArmorGlint -> getGbuffersGlint();
case SpiderEyes -> getGbuffersEntityEyes();
case Hand -> getGbuffersHand();
case Weather -> getGbuffersWeather();
case Water -> getGbuffersWater();
case HandWater -> getGbuffersHandWater();
case Final -> getCompositeFinal();
case DhTerrain -> getDhTerrain();
case DhGeneric -> getDhGeneric();
case DhWater -> getDhWater();
case DhShadow -> getDhShadow();
default -> Optional.empty();
};
}
public ProgramSource[] getDeferred() {
@@ -97,6 +97,7 @@ public class ShaderProperties {
@Getter private OptionalBoolean prepareBeforeShadow = OptionalBoolean.DEFAULT;
@Getter private List<String> sliderOptions = new ArrayList<>();
@Getter private final Map<String, List<String>> profiles = new LinkedHashMap<>();
@Getter private final Map<String, List<String>> profiles2 = new LinkedHashMap<>();
private List<String> mainScreenOptions = null;
@Getter private final Map<String, List<String>> subScreenOptions = new HashMap<>();
private Integer mainScreenColumnCount = null;
@@ -494,15 +495,15 @@ public class ShaderProperties {
customUniforms.addVariable(parts[0], parts[1], value, false);
});
handlePassDirective("uniform.", key, value, pass -> {
String[] parts = pass.split("\\.");
if (parts.length != 2) {
Iris.logger.warn("Custom uniforms sould take the form of `uniform.<type>.<name> = <expression>. Ignoring " + key);
return;
}
handlePassDirective("uniform.", key, value, pass -> {
String[] parts = pass.split("\\.");
if (parts.length != 2) {
Iris.logger.warn("Custom uniforms sould take the form of `uniform.<type>.<name> = <expression>. Ignoring " + key);
return;
}
customUniforms.addVariable(parts[0], parts[1], value, true);
});
customUniforms.addVariable(parts[0], parts[1], value, true);
});
// TODO: Buffer size directives
// TODO: Conditional program enabling directives
@@ -517,6 +518,7 @@ public class ShaderProperties {
// the last definition being used, should be tested if behavior matches OptiFine
handleWhitespacedListDirective(key, value, "sliders", sliders -> sliderOptions = sliders);
handlePrefixedWhitespacedListDirective("profile.", key, value, profiles::put);
handlePrefixedWhitespacedListDirective("profile2.", key, value, profiles2::put);
if (handleIntDirective(key, value, "screen.columns", columns -> mainScreenColumnCount = columns)) {
return;
@@ -7,7 +7,8 @@ public enum ProgramGroup {
Gbuffers("gbuffers"),
Deferred("deferred"),
Composite("composite"),
Final("final")
Final("final"),
Dh("dh")
;
private final String baseName;
@@ -1,6 +1,11 @@
package net.coderbot.iris.shaderpack.loading;
import com.gtnewhorizons.angelica.glsm.states.BlendState;
import net.coderbot.iris.gl.blending.AlphaTest;
import net.coderbot.iris.gl.blending.AlphaTestFunction;
import net.coderbot.iris.gl.blending.AlphaTestOverride;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import org.lwjgl.opengl.GL11;
import java.util.Objects;
import java.util.Optional;
@@ -26,6 +31,7 @@ public enum ProgramId {
DamagedBlock(ProgramGroup.Gbuffers, "damagedblock", Terrain),
Block(ProgramGroup.Gbuffers, "block", Terrain),
BlockTrans(ProgramGroup.Gbuffers, "block_translucent", Block, BlendModeOverride.OFF),
BeaconBeam(ProgramGroup.Gbuffers, "beaconbeam", Textured),
Item(ProgramGroup.Gbuffers, "item", TexturedLit),
@@ -33,12 +39,18 @@ public enum ProgramId {
EntitiesTrans(ProgramGroup.Gbuffers, "entities_translucent", Entities),
EntitiesGlowing(ProgramGroup.Gbuffers, "entities_glowing", Entities),
ArmorGlint(ProgramGroup.Gbuffers, "armor_glint", Textured),
SpiderEyes(ProgramGroup.Gbuffers, "spidereyes", Textured),
SpiderEyes(ProgramGroup.Gbuffers, "spidereyes", Textured,
new BlendModeOverride(new BlendState(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE)),
new AlphaTestOverride(new AlphaTest(AlphaTestFunction.GREATER, 0.0001F))),
Hand(ProgramGroup.Gbuffers, "hand", TexturedLit),
Weather(ProgramGroup.Gbuffers, "weather", TexturedLit),
Water(ProgramGroup.Gbuffers, "water", Terrain),
HandWater(ProgramGroup.Gbuffers, "hand_water", Hand),
DhTerrain(ProgramGroup.Dh, "terrain"),
DhWater(ProgramGroup.Dh, "water", DhTerrain),
DhGeneric(ProgramGroup.Dh, "generic", DhTerrain),
DhShadow(ProgramGroup.Dh, "shadow"),
Final(ProgramGroup.Final, ""),
;
@@ -47,12 +59,14 @@ public enum ProgramId {
private final String sourceName;
private final ProgramId fallback;
private final BlendModeOverride defaultBlendOverride;
private final AlphaTestOverride defaultAlphaTestOverride;
ProgramId(ProgramGroup group, String name) {
this.group = group;
this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name;
this.fallback = null;
this.defaultBlendOverride = null;
this.defaultAlphaTestOverride = null;
}
ProgramId(ProgramGroup group, String name, ProgramId fallback) {
@@ -60,6 +74,7 @@ public enum ProgramId {
this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name;
this.fallback = Objects.requireNonNull(fallback);
this.defaultBlendOverride = null;
this.defaultAlphaTestOverride = null;
}
ProgramId(ProgramGroup group, String name, ProgramId fallback, BlendModeOverride defaultBlendOverride) {
@@ -67,6 +82,15 @@ public enum ProgramId {
this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name;
this.fallback = Objects.requireNonNull(fallback);
this.defaultBlendOverride = defaultBlendOverride;
this.defaultAlphaTestOverride = null;
}
ProgramId(ProgramGroup group, String name, ProgramId fallback, BlendModeOverride defaultBlendOverride, AlphaTestOverride defaultAlphaTestOverride) {
this.group = group;
this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name;
this.fallback = Objects.requireNonNull(fallback);
this.defaultBlendOverride = defaultBlendOverride;
this.defaultAlphaTestOverride = defaultAlphaTestOverride;
}
public ProgramGroup getGroup() {
@@ -84,4 +108,8 @@ public enum ProgramId {
public BlendModeOverride getBlendModeOverride() {
return defaultBlendOverride;
}
public AlphaTestOverride getDefaultAlphaTestOverride() {
return defaultAlphaTestOverride;
}
}
@@ -1,6 +1,7 @@
package net.coderbot.iris.shaderpack.option.menu;
import com.google.common.collect.Lists;
import lombok.Getter;
import net.coderbot.iris.Iris;
import net.coderbot.iris.shaderpack.ShaderProperties;
import net.coderbot.iris.shaderpack.option.ProfileSet;
@@ -21,10 +22,12 @@ public class OptionMenuContainer {
private final List<String> usedOptions = new ArrayList<>();
private final List<String> unusedOptions = new ArrayList<>(); // To be used when screens contain a "*" element
private final Map<List<OptionMenuElement>, Integer> unusedOptionDumpQueue = new HashMap<>(); // Used by screens with "*" element
private final ProfileSet profiles;
@Getter private final ProfileSet profiles;
@Getter private final ProfileSet profiles2;
public OptionMenuContainer(ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions, ProfileSet profiles) {
this.profiles = profiles;
this.profiles2 = ProfileSet.fromTree(shaderProperties.getProfiles2(), shaderPackOptions.getOptionSet());
// note: if the Shader Pack does not provide a list of options for the main screen, then dump all options on to
// the main screen by default.
@@ -68,10 +71,6 @@ public class OptionMenuContainer {
}
}
public ProfileSet getProfiles() {
return profiles;
}
// Screens will call this when they contain a "*" element, so that the list of
// unused options can be added after all other screens have been resolved
public void queueForUnusedOptionDump(int index, List<OptionMenuElement> elementList) {
@@ -12,6 +12,7 @@ public abstract class OptionMenuElement {
private static final String ELEMENT_EMPTY = "<empty>";
private static final String ELEMENT_PROFILE = "<profile>";
private static final String ELEMENT_PROFILE2 = "<profile2>";
public static OptionMenuElement create(String elementString, OptionMenuContainer container, ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions) throws IllegalArgumentException {
// Empty element
@@ -24,6 +25,13 @@ public abstract class OptionMenuElement {
// null indicates that the element should be forgotten (not treated as empty)
return container.getProfiles().size() > 0 ? new OptionMenuProfileElement(container.getProfiles(), shaderPackOptions.getOptionSet(), shaderPackOptions.getOptionValues()) : null;
}
// Second profile element
if (ELEMENT_PROFILE2.equals(elementString)) {
// null indicates that the element should be forgotten (not treated as empty)
return container.getProfiles2().size() > 0
? ProfileElementTracker.markSecondProfileSet(new OptionMenuProfileElement(container.getProfiles2(), shaderPackOptions.getOptionSet(), shaderPackOptions.getOptionValues()))
: null;
}
// Link to sub screen element
if (elementString.startsWith("[") && elementString.endsWith("]")) {
return new OptionMenuLinkElement(elementString.substring(1, elementString.length() - 1));
@@ -0,0 +1,22 @@
package net.coderbot.iris.shaderpack.option.menu;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
public final class ProfileElementTracker {
private static final Set<Object> SECOND_PROFILE_ELEMENTS =
Collections.newSetFromMap(new WeakHashMap<>());
private ProfileElementTracker() {
}
public static <T> T markSecondProfileSet(T element) {
SECOND_PROFILE_ELEMENTS.add(element);
return element;
}
public static boolean isSecondProfileSet(Object element) {
return SECOND_PROFILE_ELEMENTS.contains(element);
}
}
@@ -11,16 +11,16 @@ public class ShadowMatrices {
// NB: These matrices are in column-major order, not row-major order like what you'd expect!
public static Matrix4f createOrthoMatrix(float halfPlaneLength) {
public static Matrix4f createOrthoMatrix(float halfPlaneLength, float nearPlane, float farPlane) {
return new Matrix4f(
// column 1
1.0f / halfPlaneLength, 0f, 0f, 0f,
// column 2
0f, 1.0f / halfPlaneLength, 0f, 0f,
// column 3
0f, 0f, 2.0f / (NEAR - FAR), 0f,
0f, 0f, 2.0f / (nearPlane - farPlane), 0f,
// column 4
0f, 0f, -(FAR + NEAR) / (FAR - NEAR), 1f
0f, 0f, -(farPlane + nearPlane) / (farPlane - nearPlane), 1f
);
}
@@ -104,7 +104,7 @@ public class ShadowMatrices {
0f, 0f, -1.000390648841858f, 1f
);
test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f));
test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f, 0.05f, 256.0f));
// const float shadowDistance = 110.0;
// /* SHADOWHPL:110.0 */
@@ -115,7 +115,7 @@ public class ShadowMatrices {
0, 0, -1.000390648841858f, 1
);
test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f));
test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f, 0.05f, 256.0f));
Matrix4f expected90Proj = new Matrix4f(
1.0f, 0.0f, 0.0f, 0.0f,
@@ -206,6 +206,20 @@ public class ShadowRenderTargets {
return framebuffer;
}
public GlFramebuffer createDHFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
}
ImmutableSet<Integer> stageWritesToMain = invert(stageWritesToAlt, drawBuffers);
GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers);
framebuffer.addDepthAttachment(mainDepth.getTextureId());
return framebuffer;
}
public GlFramebuffer createShadowFramebuffer(ImmutableSet<Integer> stageWritesToAlt, int[] drawBuffers) {
if (drawBuffers.length == 0) {
return createEmptyFramebuffer();
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
import org.embeddedt.embeddium.impl.render.viewport.Viewport;
@@ -7,7 +10,8 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Vector3d;
public class CullEverythingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class CullEverythingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private final Vector3d position = new Vector3d();
@Override
@@ -24,4 +28,16 @@ public class CullEverythingFrustum extends Frustrum implements ViewportProvider,
public Viewport sodium$createViewport() {
return new Viewport(this, position.set(xPosition, yPosition, zPosition));
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return false;
}
}
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum.advanced;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.coderbot.iris.shadows.frustum.BoxCuller;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
@@ -8,6 +11,7 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Math;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
@@ -32,7 +36,8 @@ import org.joml.Vector4f;
* are not sensitive to the specific internal ordering of planes and corners, in order to avoid potential bugs at the
* cost of slightly more computations.</p>
*/
public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private static final int MAX_CLIPPING_PLANES = 13;
/**
@@ -79,6 +84,8 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr
private final BaseClippingPlanes baseClippingPlanes = new BaseClippingPlanes();
private final boolean[] isBackArray = new boolean[6];
private int worldMinYDH;
private int worldMaxYDH;
public AdvancedShadowCullingFrustum() {
for (int i = 0; i < MAX_CLIPPING_PLANES; i++) {
@@ -86,7 +93,7 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr
}
}
public void init(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVector, BoxCuller boxCuller) {
public void init(Matrix4fc playerView, Matrix4fc playerProjection, Vector3f shadowLightVector, BoxCuller boxCuller) {
this.shadowLightVectorFromOrigin.set(shadowLightVector);
this.boxCuller = boxCuller;
this.planeCount = 0;
@@ -298,4 +305,17 @@ public class AdvancedShadowCullingFrustum extends Frustrum implements ViewportPr
return true;
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
this.worldMinYDH = worldMinBlockY;
this.worldMaxYDH = worldMaxBlockY;
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return this.isVisible(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth);
}
}
@@ -1,6 +1,7 @@
package net.coderbot.iris.shadows.frustum.advanced;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector4f;
public class BaseClippingPlanes {
@@ -13,7 +14,7 @@ public class BaseClippingPlanes {
}
}
public void init(Matrix4f view, Matrix4f projection) {
public void init(Matrix4fc view, Matrix4fc projection) {
// Transform = Transpose(Projection x View)
transformScratch.set(projection);
transformScratch.mul(view);
@@ -3,12 +3,13 @@ package net.coderbot.iris.shadows.frustum.advanced;
import net.coderbot.iris.shadows.frustum.BoxCuller;
import net.minecraft.util.AxisAlignedBB;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3f;
public class SafeZoneCullingFrustum extends AdvancedShadowCullingFrustum {
private final BoxCuller distanceCuller;
public SafeZoneCullingFrustum(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVector, BoxCuller voxelCuller, BoxCuller distanceCuller) {
public SafeZoneCullingFrustum(Matrix4fc playerView, Matrix4fc playerProjection, Vector3f shadowLightVector, BoxCuller voxelCuller, BoxCuller distanceCuller) {
super();
init(playerView, playerProjection, shadowLightVector, voxelCuller);
this.distanceCuller = distanceCuller;
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum.fallback;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.coderbot.iris.shadows.frustum.BoxCuller;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
@@ -8,9 +11,12 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Vector3d;
public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private final BoxCuller boxCuller;
private final Vector3d position = new Vector3d();
private int worldMinYDH;
private int worldMaxYDH;
public BoxCullingFrustum(BoxCuller boxCuller) {
this.boxCuller = boxCuller;
@@ -36,4 +42,17 @@ public class BoxCullingFrustum extends Frustrum implements ViewportProvider, Fru
public Viewport sodium$createViewport() {
return new Viewport(this, position.set(xPosition, yPosition, zPosition));
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
this.worldMinYDH = worldMinBlockY;
this.worldMaxYDH = worldMaxBlockY;
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return !boxCuller.isCulled(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth);
}
}
@@ -1,5 +1,8 @@
package net.coderbot.iris.shadows.frustum.fallback;
import cpw.mods.fml.common.Optional;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.util.AxisAlignedBB;
import org.embeddedt.embeddium.impl.render.viewport.Viewport;
@@ -7,7 +10,8 @@ import org.embeddedt.embeddium.impl.render.viewport.ViewportProvider;
import org.embeddedt.embeddium.impl.render.viewport.frustum.Frustum;
import org.joml.Vector3d;
public class NonCullingFrustum extends Frustrum implements ViewportProvider, Frustum {
@Optional.Interface(modid = "distanthorizons", iface = "com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum")
public class NonCullingFrustum extends Frustrum implements ViewportProvider, Frustum, IDhApiShadowCullingFrustum {
private final Vector3d position = new Vector3d();
@Override
@@ -24,4 +28,17 @@ public class NonCullingFrustum extends Frustrum implements ViewportProvider, Fru
public Viewport sodium$createViewport() {
return new Viewport(this, position.set(xPosition, yPosition, zPosition));
}
@Optional.Method(modid = "distanthorizons")
@Override
public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection) {
}
@Optional.Method(modid = "distanthorizons")
@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return true;
}
}
@@ -4,8 +4,12 @@ import com.gtnewhorizons.angelica.rendering.RenderingState;
import lombok.Getter;
import net.coderbot.iris.gl.uniform.UniformHolder;
import net.minecraft.client.Minecraft;
import org.joml.Matrix3f;
import org.joml.Vector3d;
import org.joml.Vector3dc;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector3i;
import org.joml.Vector3ic;
import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE;
import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME;
@@ -15,6 +19,8 @@ import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME;
*/
public class CameraUniforms {
private static final Minecraft client = Minecraft.getMinecraft();
private static final Vector3f tempVec3f = new Vector3f();
private static final Vector3i tempVec3i = new Vector3i();
private CameraUniforms() {
}
@@ -27,7 +33,27 @@ public class CameraUniforms {
.uniform1f(PER_FRAME, "far", CameraUniforms::getRenderDistanceInBlocks)
.uniform3d(PER_FRAME, "cameraPosition", tracker::getCurrentCameraPosition)
.uniform1f(PER_FRAME, "eyeAltitude", tracker::getCurrentCameraPositionY)
.uniform3d(PER_FRAME, "previousCameraPosition", tracker::getPreviousCameraPosition);
.uniform3d(PER_FRAME, "previousCameraPosition", tracker::getPreviousCameraPosition)
.uniform3i(PER_FRAME, "cameraPositionInt", () -> getCameraPositionInt(getUnshiftedCameraPosition()))
.uniform3f(PER_FRAME, "cameraPositionFract", () -> getCameraPositionFract(getUnshiftedCameraPosition()))
.uniform3i(PER_FRAME, "previousCameraPositionInt", () -> getCameraPositionInt(tracker.getPreviousCameraPositionUnshifted()))
.uniform3f(PER_FRAME, "previousCameraPositionFract", () -> getCameraPositionFract(tracker.getPreviousCameraPositionUnshifted()));
}
public static Vector3fc getCameraPositionFract(Vector3d originalPos) {
return tempVec3f.set(
(float) (originalPos.x - Math.floor(originalPos.x)),
(float) (originalPos.y - Math.floor(originalPos.y)),
(float) (originalPos.z - Math.floor(originalPos.z))
);
}
public static Vector3ic getCameraPositionInt(Vector3d originalPos) {
return tempVec3i.set(
(int) Math.floor(originalPos.x),
(int) Math.floor(originalPos.y),
(int) Math.floor(originalPos.z)
);
}
private static int getRenderDistanceInBlocks() {
@@ -35,7 +61,7 @@ public class CameraUniforms {
return client.gameSettings.renderDistanceChunks * 16;
}
public static Vector3dc getUnshiftedCameraPosition() {
public static Vector3d getUnshiftedCameraPosition() {
return RenderingState.INSTANCE.getCameraPosition();
}
@@ -50,10 +76,12 @@ public class CameraUniforms {
private static final double TP_RANGE = 1000;
@Getter
private Vector3d previousCameraPosition = new Vector3d();
private Vector3d previousCameraPosition = new Vector3d();
@Getter
private Vector3d currentCameraPosition = new Vector3d();
private Vector3d currentCameraPosition = new Vector3d();
private final Vector3d shift = new Vector3d();
private Vector3d previousCameraPositionUnshifted = new Vector3d();
private Vector3d currentCameraPositionUnshifted = new Vector3d();
CameraPositionTracker(FrameUpdateNotifier notifier) {
notifier.addListener(this::update);
@@ -61,7 +89,9 @@ public class CameraUniforms {
private void update() {
previousCameraPosition.set(currentCameraPosition);
previousCameraPositionUnshifted = currentCameraPositionUnshifted;
currentCameraPosition.set(getUnshiftedCameraPosition()).add(shift);
currentCameraPositionUnshifted.set(getUnshiftedCameraPosition());
updateShift();
}
@@ -104,8 +134,12 @@ public class CameraUniforms {
previousCameraPosition.z += dZ;
}
public double getCurrentCameraPositionY() {
public double getCurrentCameraPositionY() {
return currentCameraPosition.y;
}
public Vector3d getPreviousCameraPositionUnshifted() {
return previousCameraPositionUnshifted;
}
}
}
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.glsm.texture.TextureInfo;
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
import com.gtnewhorizons.angelica.client.rendering.TextureTracker;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
import net.coderbot.iris.gl.uniform.DynamicUniformHolder;
@@ -137,7 +138,10 @@ public final class CommonUniforms {
.uniform1f(PER_TICK, "rainStrength", CommonUniforms::getRainStrength)
.uniform1f(PER_TICK, "wetness", new SmoothedFloat(directives.getWetnessHalfLife(), directives.getDrynessHalfLife(), CommonUniforms::getRainStrength, updateNotifier))
.uniform3d(PER_FRAME, "skyColor", CommonUniforms::getSkyColor)
.uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor);
.uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor)
.uniform1f(PER_FRAME, "dhFarPlane", DHCompat::getFarPlane)
.uniform1f(PER_FRAME, "dhNearPlane", DHCompat::getNearPlane)
.uniform1i(PER_FRAME, "dhRenderDistance", DHCompat::getRenderDistance);
}
private static boolean isOnGround() {
@@ -14,6 +14,7 @@ public class ExternallyManagedUniforms {
addMat4(uniformHolder, "iris_ProjectionMatrix");
addMat4(uniformHolder, "iris_ProjectionMatrixInverse");
addMat4(uniformHolder, "iris_LightmapTextureMatrix");
addMat4(uniformHolder, "iris_TextureMatrix");
addMat4(uniformHolder, "u_ModelViewProjectionMatrix");
addMat3(uniformHolder, "iris_NormalMatrix");
uniformHolder.externallyManagedUniform("heavyFog", UniformType.BOOL);
@@ -1,11 +1,13 @@
package net.coderbot.iris.uniforms;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import net.coderbot.iris.compat.dh.DHCompat;
import net.coderbot.iris.gl.uniform.UniformHolder;
import net.coderbot.iris.pipeline.ShadowRenderer;
import net.coderbot.iris.shaderpack.PackDirectives;
import net.coderbot.iris.shadow.ShadowMatrices;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import java.util.function.Supplier;
@@ -20,27 +22,37 @@ public final class MatrixUniforms {
// TODO: In some cases, gbufferProjectionInverse takes on a value much different than OptiFine...
// We need to audit Mojang's linear algebra.
addMatrix(uniforms, "Projection", RenderingState.INSTANCE::getProjectionMatrix);
addDHMatrix(uniforms, "Projection", DHCompat::getProjection);
addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).peek().getModel());
addShadowMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance()));
addShadowMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance(), directives.getShadowDirectives().getNearPlane() < 0 ? -DHCompat.getRenderDistance() : directives.getShadowDirectives().getNearPlane(),
directives.getShadowDirectives().getFarPlane() < 0 ? DHCompat.getRenderDistance() : directives.getShadowDirectives().getFarPlane()));
}
private static void addMatrix(UniformHolder uniforms, String name, Supplier<Matrix4f> supplier) {
private static void addMatrix(UniformHolder uniforms, String name, Supplier<Matrix4fc> supplier) {
uniforms
.uniformMatrix(PER_FRAME, "gbuffer" + name, supplier)
.uniformMatrix(PER_FRAME, "gbuffer" + name + "Inverse", new Inverted(supplier))
.uniformMatrix(PER_FRAME, "gbufferPrevious" + name, new Previous(supplier));
}
private static void addShadowMatrix(UniformHolder uniforms, String name, Supplier<Matrix4f> supplier) {
private static void addDHMatrix(UniformHolder uniforms, String name, Supplier<Matrix4fc> supplier) {
uniforms
.uniformMatrix(PER_FRAME, "dh" + name, supplier)
.uniformMatrix(PER_FRAME, "dh" + name + "Inverse", new Inverted(supplier))
.uniformMatrix(PER_FRAME, "dhPrevious" + name, new Previous(supplier));
}
private static void addShadowMatrix(UniformHolder uniforms, String name, Supplier<Matrix4fc> supplier) {
uniforms
.uniformMatrix(PER_FRAME, "shadow" + name, supplier)
.uniformMatrix(PER_FRAME, "shadow" + name + "Inverse", new Inverted(supplier));
}
private static class Inverted implements Supplier<Matrix4f> {
private final Supplier<Matrix4f> parent;
private static class Inverted implements Supplier<Matrix4fc> {
private final Supplier<Matrix4fc> parent;
Inverted(Supplier<Matrix4f> parent) {
Inverted(Supplier<Matrix4fc> parent) {
this.parent = parent;
}
@@ -56,11 +68,11 @@ public final class MatrixUniforms {
}
private static class Previous implements Supplier<Matrix4f> {
private final Supplier<Matrix4f> parent;
private Matrix4f previous;
private static class Previous implements Supplier<Matrix4fc> {
private final Supplier<Matrix4fc> parent;
private Matrix4fc previous;
Previous(Supplier<Matrix4f> parent) {
Previous(Supplier<Matrix4fc> parent) {
this.parent = parent;
this.previous = new Matrix4f();
}
@@ -25,7 +25,8 @@ import org.joml.Vector2f;
import org.joml.Vector2i;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.joml.Vector3fc;
import org.joml.Vector3ic;
import org.joml.Vector4f;
import java.util.Collection;
@@ -116,12 +117,12 @@ public class CustomUniformFixedInputUniformsHolder {
}
@Override
public Builder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3f> value) {
public Builder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3fc> value) {
return this.put(name, new Float3VectorCachedUniform(name, updateFrequency, value));
}
@Override
public Builder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3i> value) {
public Builder uniform3i(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3ic> value) {
return this.put(name, new Int3VectorCachedUniform(name, updateFrequency, value));
}
@@ -172,7 +173,7 @@ public class CustomUniformFixedInputUniformsHolder {
@Override
public UniformHolder uniformMatrix(
UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4f> value) {
UniformUpdateFrequency updateFrequency, String name, Supplier<Matrix4fc> value) {
return this.put(name, new Float4MatrixCachedUniform(name, updateFrequency, value));
}
@@ -4,23 +4,24 @@ import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
import net.coderbot.iris.parsing.VectorType;
import org.joml.Vector3f;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import org.joml.Vector3fc;
import java.util.function.Supplier;
public class Float3VectorCachedUniform extends VectorCachedUniform<Vector3f> {
public class Float3VectorCachedUniform extends VectorCachedUniform<Vector3fc> {
public Float3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector3f> supplier) {
public Float3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector3fc> supplier) {
super(name, updateFrequency, new Vector3f(), supplier);
}
@Override
protected void setFrom(Vector3f other) {
this.cached.set(other);
protected void setFrom(Vector3fc other) {
((Vector3f)this.cached).set(other);
}
@Override
public void push(int location) {
GLStateManager.glUniform3f(location, this.cached.x, this.cached.y, this.cached.z);
GLStateManager.glUniform3f(location, this.cached.x(), this.cached.y(), this.cached.z());
}
@Override
@@ -4,21 +4,22 @@ import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
import net.coderbot.iris.parsing.MatrixType;
import org.joml.Matrix4f;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import org.joml.Matrix4fc;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.function.Supplier;
public class Float4MatrixCachedUniform extends VectorCachedUniform<Matrix4f> {
public class Float4MatrixCachedUniform extends VectorCachedUniform<Matrix4fc> {
final private FloatBuffer buffer = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
public Float4MatrixCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Matrix4f> supplier) {
public Float4MatrixCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Matrix4fc> supplier) {
super(name, updateFrequency, new Matrix4f(), supplier);
}
@Override
protected void setFrom(Matrix4f other) {
protected void setFrom(Matrix4fc other) {
((Matrix4f) this.cached).set(other);
}
@@ -4,23 +4,24 @@ import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
import net.coderbot.iris.parsing.VectorType;
import org.joml.Vector3i;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import org.joml.Vector3ic;
import java.util.function.Supplier;
public class Int3VectorCachedUniform extends VectorCachedUniform<Vector3i> {
public class Int3VectorCachedUniform extends VectorCachedUniform<Vector3ic> {
public Int3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector3i> supplier) {
public Int3VectorCachedUniform(String name, UniformUpdateFrequency updateFrequency, Supplier<Vector3ic> supplier) {
super(name, updateFrequency, new Vector3i(), supplier);
}
@Override
protected void setFrom(Vector3i other) {
this.cached.set(other);
protected void setFrom(Vector3ic other) {
((Vector3i)this.cached).set(other);
}
@Override
public void push(int location) {
GLStateManager.glUniform3i(location, this.cached.x, this.cached.y, this.cached.z);
GLStateManager.glUniform3i(location, this.cached.x(), this.cached.y(), this.cached.z());
}
@Override
@@ -1,6 +1,7 @@
package com.gtnewhorizons.angelica.mixins.early.angelica;
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import net.minecraftforge.client.ForgeHooksClient;
@@ -39,13 +40,12 @@ public abstract class MixinForgeHooksClient_CoreProfile {
@Overwrite
public static void createDisplay() throws LWJGLException {
ImageIO.setUseCache(false);
// Preserve vanilla Forge stencil support -- enabled via -Dforge.forceDisplayStencil=true by users/modpacks
final boolean wantStencil = Boolean.parseBoolean(System.getProperty("forge.forceDisplayStencil", "false"));
stencilBits = wantStencil ? 8 : 0;
// Always enable 8-bit stencil, was an option before "-Dforge.forceDisplayStencil=true"
stencilBits = 8;
final PixelFormat format = new PixelFormat().withDepthBits(24).withStencilBits(stencilBits);
final ContextAttribs attribs = new ContextAttribs(3, 3).withProfileCore(true).withForwardCompatible(true);
final ContextAttribs attribs = new ContextAttribs(3, 3).withProfileCore(true).withForwardCompatible(true).withDebug(AngelicaMod.lwjglDebug);
final MethodHandle setMajor, setMinor;
try {
final Field majorField = ContextAttribs.class.getDeclaredField("majorVersion");
@@ -0,0 +1,125 @@
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import net.minecraft.client.renderer.ItemRenderer;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.opengl.GL11;
import org.spongepowered.asm.mixin.Mixin;
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;
/**
* Fix enchantment glint z-fighting on held item edges using stencil masking.
*
* Vanilla uses GL_EQUAL to restrict the glint to item pixels, but GPU depth
* non-determinism between draw calls causes GL_EQUAL to fail on edge quads.
*
* This mixin uses a stencil-based check instead of a GL_EQUAL check.
* 1. During item render: write stencil value 1 wherever the item draws.
* 2. During each glint renderItemIn2D call:
* a. Pre-pass: no color/depth writes, GL_LEQUAL depth test, increment the stencil 1→2
* where depth passes. This determines pixel ownership without corrupting the depth buffer (damn potions...)
* b. Color pass: draw only where stencil == 2, GL_ALWAYS depth test, decrement the stencil
* 2→1 to reset for the next glint pass.
*/
@Mixin(value = ItemRenderer.class, priority = 1100)
public class MixinItemRenderer_EdgeDepth {
@Unique private static boolean angelica$glintMode = false;
@Unique private static boolean angelica$inPrepass = false;
// Item render: write stencil value 1 at all visible item pixels
@Inject(
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 = 0, remap = true),
remap = false
)
private void angelica$stencilWriteStart(CallbackInfo ci) {
GLStateManager.glEnable(GL11.GL_STENCIL_TEST);
GLStateManager.glStencilMask(0xFF);
GLStateManager.glClearStencil(0);
GLStateManager.glClear(GL11.GL_STENCIL_BUFFER_BIT);
GLStateManager.glStencilFunc(GL11.GL_ALWAYS, 1, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
}
@Inject(
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 = 0, remap = true, shift = At.Shift.AFTER),
remap = false
)
private void angelica$stencilWriteEnd(CallbackInfo ci) {
GLStateManager.glStencilMask(0x00);
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
}
// Glint section: replace GL_EQUAL with stencil-based masking
@Redirect(
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", ordinal = 0, remap = false),
remap = false
)
private void angelica$glintStart(int func) {
angelica$glintMode = true;
GLStateManager.glEnable(GL11.GL_STENCIL_TEST);
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
}
@Redirect(
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", ordinal = 1, remap = false),
remap = false
)
private void angelica$glintEnd(int func) {
angelica$glintMode = false;
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glDepthMask(true);
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
GLStateManager.glStencilMask(0xFF);
}
// Stencil pre-pass inside renderItemIn2D when in glint mode
@WrapMethod(method = "renderItemIn2D")
private static void angelica$glintPrepass(Tessellator tess, float minU, float minV, float maxU, float maxV,
int w, int h, float thickness, Operation<Void> original) {
if (!angelica$glintMode || angelica$inPrepass) {
original.call(tess, minU, minV, maxU, maxV, w, h, thickness);
return;
}
angelica$inPrepass = true;
// Pre-pass: determine pixel ownership via GL_LEQUAL depth test.
GLStateManager.glColorMask(false, false, false, false);
GLStateManager.glDepthMask(false);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glStencilMask(0xFF);
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_INCR);
original.call(tess, minU, minV, maxU, maxV, w, h, thickness);
// Color pass: draw only at pre-pass pixels.
GLStateManager.glColorMask(true, true, true, true);
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 2, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_DECR);
GLStateManager.glDepthFunc(GL11.GL_ALWAYS);
original.call(tess, minU, minV, maxU, maxV, w, h, thickness);
// Restore state for the next glint renderItemIn2D call
GLStateManager.glStencilMask(0x00);
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
angelica$inPrepass = false;
}
}
@@ -24,7 +24,8 @@ public class MixinRendererLivingEntity_EyeDepth {
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/ModelBase;render(Lnet/minecraft/entity/Entity;FFFFFF)V"),
slice = @Slice(
from = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;shouldRenderPass(Lnet/minecraft/entity/EntityLivingBase;IF)I")
from = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;shouldRenderPass(Lnet/minecraft/entity/EntityLivingBase;IF)I"),
to = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V")
)
)
private void angelica$eyePassPolygonOffset(ModelBase instance, Entity entity, float a, float b, float c, float d, float e, float f, Operation<Void> original) {
@@ -1,5 +1,6 @@
package com.gtnewhorizons.angelica.mixins.early.celeritas.features.mipmaps;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.rendering.celeritas.SpriteExtension;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import org.embeddedt.embeddium.api.util.ColorABGR;
@@ -29,9 +30,23 @@ public abstract class MixinTextureAtlasSprite implements SpriteExtension {
if (this.framesTextureData.isEmpty() || this.framesTextureData.get(0) == null) {
return;
}
if (celeritas$isAlwaysTranslucent(this.iconName)) {
this.celeritas$transparencyLevel = SpriteTransparencyLevel.TRANSLUCENT;
return;
}
celeritas$processTransparentImages(this.framesTextureData.get(0)[0], level > 0 && !iconName.contains("leaves"));
}
@Unique
private static boolean celeritas$isAlwaysTranslucent(String name) {
final String[] list = AngelicaConfig.alwaysTranslucentSprites;
if (list == null || list.length == 0) return false;
for (String s : list) {
if (name.equals(s)) return true;
}
return false;
}
// Ordinals: OPAQUE=0, TRANSPARENT=1, TRANSLUCENT=2
@Unique private static final int ORDINAL_OPAQUE = SpriteTransparencyLevel.OPAQUE.ordinal();
@Unique private static final int ORDINAL_TRANSPARENT = SpriteTransparencyLevel.TRANSPARENT.ordinal();
@@ -0,0 +1,249 @@
package com.gtnewhorizons.angelica.mixins.early.celeritas.light;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import com.gtnewhorizons.angelica.api.ExtAoFaceData;
import com.gtnewhorizons.angelica.api.ExtLightDataAccess;
import com.gtnewhorizons.angelica.rendering.celeritas.compat.AoHelper;
import org.embeddedt.embeddium.impl.model.light.data.LightDataAccess;
import org.embeddedt.embeddium.impl.model.light.smooth.AoFaceData;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
import org.spongepowered.asm.mixin.Mixin;
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;
@Mixin(value = AoFaceData.class, remap = false)
public class MixinAoFaceData implements ExtAoFaceData {
@Unique private final float[] angelica$rl = new float[4];
@Unique private final float[] angelica$gl = new float[4];
@Unique private final float[] angelica$bl = new float[4];
@Unique private final float[] angelica$skyRl = new float[4];
@Unique private final float[] angelica$skyGl = new float[4];
@Unique private final float[] angelica$skyBl = new float[4];
@Override
public float[] angelica$getRl() {
return angelica$rl;
}
@Override
public float[] angelica$getGl() {
return angelica$gl;
}
@Override
public float[] angelica$getBl() {
return angelica$bl;
}
@Override
public float angelica$getBlendedR(float[] w) {
return angelica$rl[0] * w[0] + angelica$rl[1] * w[1] + angelica$rl[2] * w[2] + angelica$rl[3] * w[3];
}
@Override
public float angelica$getBlendedG(float[] w) {
return angelica$gl[0] * w[0] + angelica$gl[1] * w[1] + angelica$gl[2] * w[2] + angelica$gl[3] * w[3];
}
@Override
public float angelica$getBlendedB(float[] w) {
return angelica$bl[0] * w[0] + angelica$bl[1] * w[1] + angelica$bl[2] * w[2] + angelica$bl[3] * w[3];
}
@Override
public float[] angelica$getSkyRl() {
return angelica$skyRl;
}
@Override
public float[] angelica$getSkyGl() {
return angelica$skyGl;
}
@Override
public float[] angelica$getSkyBl() {
return angelica$skyBl;
}
@Override
public float angelica$getBlendedSkyR(float[] w) {
return angelica$skyRl[0] * w[0] + angelica$skyRl[1] * w[1] + angelica$skyRl[2] * w[2] + angelica$skyRl[3] * w[3];
}
@Override
public float angelica$getBlendedSkyG(float[] w) {
return angelica$skyGl[0] * w[0] + angelica$skyGl[1] * w[1] + angelica$skyGl[2] * w[2] + angelica$skyGl[3] * w[3];
}
@Override
public float angelica$getBlendedSkyB(float[] w) {
return angelica$skyBl[0] * w[0] + angelica$skyBl[1] * w[1] + angelica$skyBl[2] * w[2] + angelica$skyBl[3] * w[3];
}
@Inject(method = "initLightData", at = @At("TAIL"))
private void angelica$initRGBData(LightDataAccess cache, int x, int y, int z, ModelQuadFacing direction, boolean offset, CallbackInfo ci) {
final ExtLightDataAccess rgbCache = (ExtLightDataAccess) cache;
final boolean doBlock = rgbCache.angelica$isRGBEnabled();
final boolean doSky = rgbCache.angelica$isSkyRGBEnabled();
if (!doBlock && !doSky) return;
final int adjX, adjY, adjZ;
if (offset) {
adjX = x + direction.getStepX();
adjY = y + direction.getStepY();
adjZ = z + direction.getStepZ();
} else {
adjX = x;
adjY = y;
adjZ = z;
}
final ModelQuadFacing[] faces = AoHelper.getFaces(direction);
// Edge opacity
final boolean e0op = LightDataAccess.unpackOP(cache.get(adjX, adjY, adjZ, faces[0]));
final boolean e1op = LightDataAccess.unpackOP(cache.get(adjX, adjY, adjZ, faces[1]));
final boolean e2op = LightDataAccess.unpackOP(cache.get(adjX, adjY, adjZ, faces[2]));
final boolean e3op = LightDataAccess.unpackOP(cache.get(adjX, adjY, adjZ, faces[3]));
// Center
final int adjWord = cache.get(adjX, adjY, adjZ);
final boolean useFallback = offset && LightDataAccess.unpackFO(adjWord);
final int caX = useFallback ? x : adjX;
final int caY = useFallback ? y : adjY;
final int caZ = useFallback ? z : adjZ;
final int caIdx = rgbCache.angelica$getIndex(caX, caY, caZ);
// Edge world coords
final int e0x = adjX + faces[0].getStepX(), e0y = adjY + faces[0].getStepY(), e0z = adjZ + faces[0].getStepZ();
final int e1x = adjX + faces[1].getStepX(), e1y = adjY + faces[1].getStepY(), e1z = adjZ + faces[1].getStepZ();
final int e2x = adjX + faces[2].getStepX(), e2y = adjY + faces[2].getStepY(), e2z = adjZ + faces[2].getStepZ();
final int e3x = adjX + faces[3].getStepX(), e3y = adjY + faces[3].getStepY(), e3z = adjZ + faces[3].getStepZ();
// Edge indices
final int e0Idx = rgbCache.angelica$getIndex(e0x, e0y, e0z);
final int e1Idx = rgbCache.angelica$getIndex(e1x, e1y, e1z);
final int e2Idx = rgbCache.angelica$getIndex(e2x, e2y, e2z);
final int e3Idx = rgbCache.angelica$getIndex(e3x, e3y, e3z);
// Corner world coords + indices; only compute if not occluded
final int c0x, c0y, c0z, c0Idx;
if (e2op && e0op) { c0x = c0y = c0z = c0Idx = 0; }
else {
c0x = e0x + faces[2].getStepX(); c0y = e0y + faces[2].getStepY(); c0z = e0z + faces[2].getStepZ();
c0Idx = rgbCache.angelica$getIndex(c0x, c0y, c0z);
}
final int c1x, c1y, c1z, c1Idx;
if (e3op && e0op) { c1x = c1y = c1z = c1Idx = 0; }
else {
c1x = e0x + faces[3].getStepX(); c1y = e0y + faces[3].getStepY(); c1z = e0z + faces[3].getStepZ();
c1Idx = rgbCache.angelica$getIndex(c1x, c1y, c1z);
}
final int c2x, c2y, c2z, c2Idx;
if (e2op && e1op) { c2x = c2y = c2z = c2Idx = 0; }
else {
c2x = e1x + faces[2].getStepX(); c2y = e1y + faces[2].getStepY(); c2z = e1z + faces[2].getStepZ();
c2Idx = rgbCache.angelica$getIndex(c2x, c2y, c2z);
}
final int c3x, c3y, c3z, c3Idx;
if (e3op && e1op) { c3x = c3y = c3z = c3Idx = 0; }
else {
c3x = e1x + faces[3].getStepX(); c3y = e1y + faces[3].getStepY(); c3z = e1z + faces[3].getStepZ();
c3Idx = rgbCache.angelica$getIndex(c3x, c3y, c3z);
}
final long caF = rgbCache.angelica$getFusedByIndex(caIdx, caX, caY, caZ);
final long e0F = rgbCache.angelica$getFusedByIndex(e0Idx, e0x, e0y, e0z);
final long e1F = rgbCache.angelica$getFusedByIndex(e1Idx, e1x, e1y, e1z);
final long e2F = rgbCache.angelica$getFusedByIndex(e2Idx, e2x, e2y, e2z);
final long e3F = rgbCache.angelica$getFusedByIndex(e3Idx, e3x, e3y, e3z);
final long c0F = (e2op && e0op) ? e0F : rgbCache.angelica$getFusedByIndex(c0Idx, c0x, c0y, c0z);
final long c1F = (e3op && e0op) ? e0F : rgbCache.angelica$getFusedByIndex(c1Idx, c1x, c1y, c1z);
final long c2F = (e2op && e1op) ? e1F : rgbCache.angelica$getFusedByIndex(c2Idx, c2x, c2y, c2z);
final long c3F = (e3op && e1op) ? e1F : rgbCache.angelica$getFusedByIndex(c3Idx, c3x, c3y, c3z);
if (doBlock) {
final int caRGB = (int)(caF >>> 32);
final int e0RGB = (int)(e0F >>> 32);
final int e1RGB = (int)(e1F >>> 32);
final int e2RGB = (int)(e2F >>> 32);
final int e3RGB = (int)(e3F >>> 32);
final int c0RGB = (int)(c0F >>> 32);
final int c1RGB = (int)(c1F >>> 32);
final int c2RGB = (int)(c2F >>> 32);
final int c3RGB = (int)(c3F >>> 32);
final int caR = BlockLightProvider.unpackR(caRGB), caG = BlockLightProvider.unpackG(caRGB), caB = BlockLightProvider.unpackB(caRGB);
final int e0R = BlockLightProvider.unpackR(e0RGB), e0G = BlockLightProvider.unpackG(e0RGB), e0B = BlockLightProvider.unpackB(e0RGB);
final int e1R = BlockLightProvider.unpackR(e1RGB), e1G = BlockLightProvider.unpackG(e1RGB), e1B = BlockLightProvider.unpackB(e1RGB);
final int e2R = BlockLightProvider.unpackR(e2RGB), e2G = BlockLightProvider.unpackG(e2RGB), e2B = BlockLightProvider.unpackB(e2RGB);
final int e3R = BlockLightProvider.unpackR(e3RGB), e3G = BlockLightProvider.unpackG(e3RGB), e3B = BlockLightProvider.unpackB(e3RGB);
final int c0R = BlockLightProvider.unpackR(c0RGB), c0G = BlockLightProvider.unpackG(c0RGB), c0B = BlockLightProvider.unpackB(c0RGB);
final int c1R = BlockLightProvider.unpackR(c1RGB), c1G = BlockLightProvider.unpackG(c1RGB), c1B = BlockLightProvider.unpackB(c1RGB);
final int c2R = BlockLightProvider.unpackR(c2RGB), c2G = BlockLightProvider.unpackG(c2RGB), c2B = BlockLightProvider.unpackB(c2RGB);
final int c3R = BlockLightProvider.unpackR(c3RGB), c3G = BlockLightProvider.unpackG(c3RGB), c3B = BlockLightProvider.unpackB(c3RGB);
angelica$rl[0] = (e3R + e0R + c1R + caR) * 0.25f;
angelica$gl[0] = (e3G + e0G + c1G + caG) * 0.25f;
angelica$bl[0] = (e3B + e0B + c1B + caB) * 0.25f;
angelica$rl[1] = (e2R + e0R + c0R + caR) * 0.25f;
angelica$gl[1] = (e2G + e0G + c0G + caG) * 0.25f;
angelica$bl[1] = (e2B + e0B + c0B + caB) * 0.25f;
angelica$rl[2] = (e2R + e1R + c2R + caR) * 0.25f;
angelica$gl[2] = (e2G + e1G + c2G + caG) * 0.25f;
angelica$bl[2] = (e2B + e1B + c2B + caB) * 0.25f;
angelica$rl[3] = (e3R + e1R + c3R + caR) * 0.25f;
angelica$gl[3] = (e3G + e1G + c3G + caG) * 0.25f;
angelica$bl[3] = (e3B + e1B + c3B + caB) * 0.25f;
}
if (doSky) {
final int caSky = (int)(caF & 0xFFFFFFFFL);
final int e0Sky = (int)(e0F & 0xFFFFFFFFL);
final int e1Sky = (int)(e1F & 0xFFFFFFFFL);
final int e2Sky = (int)(e2F & 0xFFFFFFFFL);
final int e3Sky = (int)(e3F & 0xFFFFFFFFL);
final int c0Sky = (int)(c0F & 0xFFFFFFFFL);
final int c1Sky = (int)(c1F & 0xFFFFFFFFL);
final int c2Sky = (int)(c2F & 0xFFFFFFFFL);
final int c3Sky = (int)(c3F & 0xFFFFFFFFL);
final int caR = BlockLightProvider.unpackR(caSky), caG = BlockLightProvider.unpackG(caSky), caB = BlockLightProvider.unpackB(caSky);
final int e0R = BlockLightProvider.unpackR(e0Sky), e0G = BlockLightProvider.unpackG(e0Sky), e0B = BlockLightProvider.unpackB(e0Sky);
final int e1R = BlockLightProvider.unpackR(e1Sky), e1G = BlockLightProvider.unpackG(e1Sky), e1B = BlockLightProvider.unpackB(e1Sky);
final int e2R = BlockLightProvider.unpackR(e2Sky), e2G = BlockLightProvider.unpackG(e2Sky), e2B = BlockLightProvider.unpackB(e2Sky);
final int e3R = BlockLightProvider.unpackR(e3Sky), e3G = BlockLightProvider.unpackG(e3Sky), e3B = BlockLightProvider.unpackB(e3Sky);
final int c0R = BlockLightProvider.unpackR(c0Sky), c0G = BlockLightProvider.unpackG(c0Sky), c0B = BlockLightProvider.unpackB(c0Sky);
final int c1R = BlockLightProvider.unpackR(c1Sky), c1G = BlockLightProvider.unpackG(c1Sky), c1B = BlockLightProvider.unpackB(c1Sky);
final int c2R = BlockLightProvider.unpackR(c2Sky), c2G = BlockLightProvider.unpackG(c2Sky), c2B = BlockLightProvider.unpackB(c2Sky);
final int c3R = BlockLightProvider.unpackR(c3Sky), c3G = BlockLightProvider.unpackG(c3Sky), c3B = BlockLightProvider.unpackB(c3Sky);
angelica$skyRl[0] = (e3R + e0R + c1R + caR) * 0.25f;
angelica$skyGl[0] = (e3G + e0G + c1G + caG) * 0.25f;
angelica$skyBl[0] = (e3B + e0B + c1B + caB) * 0.25f;
angelica$skyRl[1] = (e2R + e0R + c0R + caR) * 0.25f;
angelica$skyGl[1] = (e2G + e0G + c0G + caG) * 0.25f;
angelica$skyBl[1] = (e2B + e0B + c0B + caB) * 0.25f;
angelica$skyRl[2] = (e2R + e1R + c2R + caR) * 0.25f;
angelica$skyGl[2] = (e2G + e1G + c2G + caG) * 0.25f;
angelica$skyBl[2] = (e2B + e1B + c2B + caB) * 0.25f;
angelica$skyRl[3] = (e3R + e1R + c3R + caR) * 0.25f;
angelica$skyGl[3] = (e3G + e1G + c3G + caG) * 0.25f;
angelica$skyBl[3] = (e3B + e1B + c3B + caB) * 0.25f;
}
}
}
@@ -0,0 +1,82 @@
package com.gtnewhorizons.angelica.mixins.early.celeritas.light;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import com.gtnewhorizons.angelica.api.ExtLightDataAccess;
import com.gtnewhorizons.angelica.api.ExtQuadLightData;
import org.embeddedt.embeddium.impl.model.light.data.LightDataAccess;
import org.embeddedt.embeddium.impl.model.light.data.QuadLightData;
import org.embeddedt.embeddium.impl.model.light.flat.FlatLightPipeline;
import org.embeddedt.embeddium.impl.model.quad.ModelQuadView;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFlags;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = FlatLightPipeline.class, remap = false)
public class MixinFlatLightPipeline {
@Shadow @Final private LightDataAccess lightCache;
@Inject(method = "calculate", at = @At("TAIL"))
private void angelica$populateRGBFlat(ModelQuadView quad, int x, int y, int z, QuadLightData out, ModelQuadFacing cullFace, ModelQuadFacing lightFace, boolean shade, boolean applyAoDepthBlending, CallbackInfo ci) {
final ExtLightDataAccess rgbCache = (ExtLightDataAccess) this.lightCache;
final ExtQuadLightData outExt = (ExtQuadLightData) out;
final boolean blockEnabled = rgbCache.angelica$isRGBEnabled();
final boolean skyEnabled = rgbCache.angelica$isSkyRGBEnabled();
if (!blockEnabled && !skyEnabled) {
outExt.angelica$setRGBValid(false);
outExt.angelica$setSkyRGBValid(false);
return;
}
final int lx, ly, lz;
if (cullFace.isDirection()) {
lx = x + cullFace.getStepX();
ly = y + cullFace.getStepY();
lz = z + cullFace.getStepZ();
} else {
final int flags = quad.getFlags();
if ((flags & ModelQuadFlags.IS_ALIGNED) != 0 || ((flags & ModelQuadFlags.IS_PARALLEL) != 0 && LightDataAccess.unpackFC(this.lightCache.get(x, y, z)))) {
lx = x + lightFace.getStepX();
ly = y + lightFace.getStepY();
lz = z + lightFace.getStepZ();
} else {
lx = x;
ly = y;
lz = z;
}
}
// Block RGB
if (blockEnabled) {
final int rgb = rgbCache.angelica$getRGB(lx, ly, lz);
final float r = BlockLightProvider.unpackR(rgb), g = BlockLightProvider.unpackG(rgb), b = BlockLightProvider.unpackB(rgb);
final float[] ra = outExt.angelica$getR(), ga = outExt.angelica$getG(), ba = outExt.angelica$getB();
ra[0] = ra[1] = ra[2] = ra[3] = r;
ga[0] = ga[1] = ga[2] = ga[3] = g;
ba[0] = ba[1] = ba[2] = ba[3] = b;
outExt.angelica$setRGBValid(true);
} else {
outExt.angelica$setRGBValid(false);
}
// Sky RGB
if (skyEnabled) {
final int skyRgb = rgbCache.angelica$getSkyRGB(lx, ly, lz);
final float r = BlockLightProvider.unpackR(skyRgb), g = BlockLightProvider.unpackG(skyRgb), b = BlockLightProvider.unpackB(skyRgb);
final float[] ra = outExt.angelica$getSkyR(), ga = outExt.angelica$getSkyG(), ba = outExt.angelica$getSkyB();
ra[0] = ra[1] = ra[2] = ra[3] = r;
ga[0] = ga[1] = ga[2] = ga[3] = g;
ba[0] = ba[1] = ba[2] = ba[3] = b;
outExt.angelica$setSkyRGBValid(true);
} else {
outExt.angelica$setSkyRGBValid(false);
}
}
}
@@ -0,0 +1,215 @@
package com.gtnewhorizons.angelica.mixins.early.celeritas.light;
import com.gtnewhorizons.angelica.api.BlockLightProvider;
import com.gtnewhorizons.angelica.api.ExtLightDataAccess;
import com.gtnewhorizons.angelica.api.ExtLightDataCache;
import com.gtnewhorizons.angelica.api.SectionLightData;
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
import com.gtnewhorizons.angelica.rendering.celeritas.world.WorldSlice;
import net.minecraft.world.IBlockAccess;
import org.embeddedt.embeddium.impl.model.light.data.LightDataAccess;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
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;
import java.util.Arrays;
@Mixin(value = LightDataAccess.class, remap = false)
public abstract class MixinLightDataAccess implements ExtLightDataAccess {
@Unique private static final int ANGELICA$CACHE_SIZE = 20 * 20 * 20;
@Unique private static final int ANGELICA$SENTINEL = 0x1000;
@Shadow
private int index(int x, int y, int z) {
throw new AssertionError();
}
/** Fused cache: upper 32 bits = block RGB word, lower 32 bits = sky RGB word. Zero = uncached. */
@Unique private long[] angelica$fusedLight;
@Unique private boolean angelica$rgbEnabled;
@Unique private boolean angelica$skyRgbEnabled;
@Unique private BlockLightProvider angelica$provider;
@Unique private IBlockAccess angelica$blockAccess;
@Inject(method = "reset", at = @At("TAIL"))
private void angelica$resetRGB(int minBlockX, int minBlockY, int minBlockZ, CallbackInfo ci) {
angelica$rgbEnabled = BlockLightProvider.isRegistered();
angelica$provider = BlockLightProvider.getInstance();
angelica$blockAccess = ((ExtLightDataCache) this).angelica$getBlockAccess();
angelica$skyRgbEnabled = angelica$rgbEnabled;
if (angelica$rgbEnabled) {
if (angelica$fusedLight == null) {
angelica$fusedLight = new long[ANGELICA$CACHE_SIZE];
} else {
Arrays.fill(angelica$fusedLight, 0L);
}
}
}
@Override
public int angelica$getRGB(int x, int y, int z) {
if (!angelica$rgbEnabled) return 0;
final int idx = this.index(x, y, z);
return angelica$getBlockFromFused(idx, x, y, z);
}
@Override
public int angelica$getRGB(int x, int y, int z, ModelQuadFacing dir) {
return angelica$getRGB(
x + dir.getStepX(),
y + dir.getStepY(),
z + dir.getStepZ());
}
@Override
public int angelica$getRGB(int x, int y, int z, ModelQuadFacing d1, ModelQuadFacing d2) {
return angelica$getRGB(
x + d1.getStepX() + d2.getStepX(),
y + d1.getStepY() + d2.getStepY(),
z + d1.getStepZ() + d2.getStepZ());
}
@Override
public boolean angelica$isRGBEnabled() {
return angelica$rgbEnabled;
}
@Override
public int angelica$getSkyRGB(int x, int y, int z) {
if (!angelica$skyRgbEnabled) return 0;
final int idx = this.index(x, y, z);
return angelica$getSkyFromFused(idx, x, y, z);
}
@Override
public int angelica$getSkyRGB(int x, int y, int z, ModelQuadFacing dir) {
return angelica$getSkyRGB(
x + dir.getStepX(),
y + dir.getStepY(),
z + dir.getStepZ());
}
@Override
public int angelica$getSkyRGB(int x, int y, int z, ModelQuadFacing d1, ModelQuadFacing d2) {
return angelica$getSkyRGB(
x + d1.getStepX() + d2.getStepX(),
y + d1.getStepY() + d2.getStepY(),
z + d1.getStepZ() + d2.getStepZ());
}
@Override
public boolean angelica$isSkyRGBEnabled() {
return angelica$skyRgbEnabled;
}
@Override
public int angelica$getIndex(int x, int y, int z) {
return this.index(x, y, z);
}
@Override
public int angelica$getRGBByIndex(int idx, int x, int y, int z) {
if (!angelica$rgbEnabled) return 0;
return angelica$getBlockFromFused(idx, x, y, z);
}
@Override
public int angelica$getSkyRGBByIndex(int idx, int x, int y, int z) {
if (!angelica$skyRgbEnabled) return 0;
return angelica$getSkyFromFused(idx, x, y, z);
}
@Override
public long angelica$getFusedByIndex(int idx, int x, int y, int z) {
long fused = angelica$fusedLight[idx];
if (fused == 0L) {
fused = angelica$fusedLight[idx] = angelica$computeFused(x, y, z);
}
return fused;
}
@Unique
private int angelica$getBlockFromFused(int idx, int x, int y, int z) {
long fused = angelica$fusedLight[idx];
if (fused == 0L) {
fused = angelica$fusedLight[idx] = angelica$computeFused(x, y, z);
}
return (int)(fused >>> 32);
}
@Unique
private int angelica$getSkyFromFused(int idx, int x, int y, int z) {
long fused = angelica$fusedLight[idx];
if (fused == 0L) {
fused = angelica$fusedLight[idx] = angelica$computeFused(x, y, z);
}
return (int)(fused & 0xFFFFFFFFL);
}
@Unique
private long angelica$computeFused(int x, int y, int z) {
final IBlockAccess blockAccess = angelica$blockAccess;
if (blockAccess instanceof WorldSlice ws) {
int blockRGB = 0xFFFF; // sentinel: no data
int skyRGB = 0xFFFF;
final SectionLightData data = ws.getSectionLightData(x, y, z);
if (data != null) {
final long fused = data.getRGBAndSkyRGB(x & 15, y & 15, z & 15);
blockRGB = (int)(fused >>> 16) & 0xFFFF;
skyRGB = (int)fused & 0xFFFF;
}
// Overlay dynamic light RGB (thread-safe: uses pre-filtered chunk-local sources)
final var dlSources = ws.getChunkLightSources();
if (dlSources != null && !dlSources.isEmpty()) {
final int dlRGB = ws.getDynamicLightsInstance()
.getDynamicLightRGBFromSources(x + 0.5, y + 0.5, z + 0.5, dlSources);
if (dlRGB != 0) {
blockRGB = angelica$mergeMaxRGB(blockRGB, dlRGB);
}
}
final long blockWord = (blockRGB == 0xFFFF) ? ANGELICA$SENTINEL : (blockRGB | ANGELICA$SENTINEL);
final long skyWord = (skyRGB == 0xFFFF) ? ANGELICA$SENTINEL : (skyRGB | ANGELICA$SENTINEL);
return (blockWord << 32) | (skyWord & 0xFFFFFFFFL);
}
final BlockLightProvider provider = angelica$provider;
int brgb = provider.getBlockLightRGB(blockAccess, x, y, z);
final int srgb = provider.getSkyLightRGB(blockAccess, x, y, z);
if (DynamicLights.isEnabled()) {
final int dlRGB = DynamicLights.get().getDynamicLightRGB(x + 0.5, y + 0.5, z + 0.5);
if (dlRGB != 0) {
brgb = angelica$mergeMaxRGB(brgb, dlRGB);
}
}
final long blockWord = (brgb == -1) ? ANGELICA$SENTINEL : (brgb | ANGELICA$SENTINEL);
final long skyWord = (srgb == -1) ? ANGELICA$SENTINEL : (srgb | ANGELICA$SENTINEL);
return (blockWord << 32) | (skyWord & 0xFFFFFFFFL);
}
/** Max-per-channel merge. Treats sentinel (0xFFFF or -1) as (0,0,0). */
@Unique
private static int angelica$mergeMaxRGB(int staticRGB, int dynamicRGB) {
final int sR = (staticRGB == 0xFFFF || staticRGB == -1) ? 0 : BlockLightProvider.unpackR(staticRGB);
final int sG = (staticRGB == 0xFFFF || staticRGB == -1) ? 0 : BlockLightProvider.unpackG(staticRGB);
final int sB = (staticRGB == 0xFFFF || staticRGB == -1) ? 0 : BlockLightProvider.unpackB(staticRGB);
return BlockLightProvider.packRGB(
Math.max(sR, BlockLightProvider.unpackR(dynamicRGB)),
Math.max(sG, BlockLightProvider.unpackG(dynamicRGB)),
Math.max(sB, BlockLightProvider.unpackB(dynamicRGB)));
}
}
Loaded 100 of 105 files, more files were not shown because too many files have changed in this diff. Show more