mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcc8d8deed | ||
|
|
5dc4f1fab8 | ||
|
|
d3cea1bfe4 | ||
|
|
5db2b248d7 | ||
|
|
21ab526284 | ||
|
|
4c8ea679ef | ||
|
|
2317379df2 | ||
|
|
24dae49c7f | ||
|
|
865de3cbab |
No files matched your search
@@ -50,6 +50,7 @@ Targets GL 3.3+ core profile
|
||||
* CodeChicken[Core](https://github.com/GTNewHorizons/CodeChickenCore/releases)/[Lib](https://github.com/GTNewHorizons/CodeChickenLib/releases) <1.2.0 - Threading issues, use 1.3.0+
|
||||
* Neodymium - Untested, but unlikely to be compatible. (Chunk Meshing is definitely incompatible, other features might work depending on config)
|
||||
* SmoothFont - Equivalent functionality added
|
||||
* ClientFixer - Use a resource pack like [GTNH-FTI-Standard-Font](https://github.com/Eldrinn-Elantey/GTNH-FTI-Standard-Font)
|
||||
|
||||
# Credits
|
||||
* ShadersMod
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import xyz.wagyourtail.jvmdg.gradle.flags.DowngradeFlags
|
||||
import xyz.wagyourtail.jvmdg.gradle.task.DowngradeJar
|
||||
import xyz.wagyourtail.jvmdg.gradle.task.files.DowngradeFiles
|
||||
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhconvention")
|
||||
}
|
||||
|
||||
tasks.withType<DowngradeJar>().configureEach { logLevel.set("FATAL") }
|
||||
tasks.withType<DowngradeFiles>().configureEach { logLevel.set("FATAL") }
|
||||
|
||||
minecraft {
|
||||
extraRunJvmArguments.add("-Dangelica.enableTestBlocks=true")
|
||||
extraRunJvmArguments.add("-Dangelica.dumpClass=true")
|
||||
|
||||
@@ -124,6 +124,7 @@ tasks.withType<DowngradeFiles>().configureEach {
|
||||
downgradeTo.set(JavaVersion.VERSION_1_8)
|
||||
multiReleaseOriginal.set(false)
|
||||
multiReleaseVersions.set(emptySet())
|
||||
logLevel.set("FATAL")
|
||||
}
|
||||
|
||||
val downgradeDepsForTest by tasks.registering(DowngradeFiles::class) {
|
||||
@@ -139,6 +140,7 @@ val downgradeMainClasses by tasks.registering(DowngradeFiles::class) {
|
||||
val downgradeTestClasses by tasks.registering(DowngradeFiles::class) {
|
||||
inputCollection = sourceSets["test"].output.classesDirs
|
||||
classpath = sourceSets["test"].compileClasspath
|
||||
sourceSets["test"].output.classesDirs.files.forEach { outputs.dir(temporaryDir.resolve(it.name)) }
|
||||
dependsOn(tasks.named("testClasses"))
|
||||
}
|
||||
|
||||
@@ -174,6 +176,19 @@ tasks.test {
|
||||
jvmArgs("-Djava.library.path=${extractNatives.get().property("destinationFolder").let { (it as DirectoryProperty).asFile.get().path }}")
|
||||
}
|
||||
|
||||
val verifyTestsRan by tasks.registering {
|
||||
val resultsDir = layout.buildDirectory.dir("test-results/test")
|
||||
dependsOn(tasks.test)
|
||||
doLast {
|
||||
val dir = resultsDir.get().asFile
|
||||
val xmls = dir.listFiles { f -> f.name.startsWith("TEST-") && f.name.endsWith(".xml") } ?: emptyArray()
|
||||
check(xmls.isNotEmpty()) {
|
||||
":glsm:test produced no TEST-*.xml in $dir - test task likely went NO-SOURCE"
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.check { dependsOn(verifyTestsRan) }
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
|
||||
@@ -11,6 +11,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@@ -112,6 +113,7 @@ public class CompatUniformManager {
|
||||
private static final FloatBuffer clipPlaneBuf = BufferUtils.createFloatBuffer(32); // 8 planes * vec4
|
||||
private static final Matrix3f normalMatrix = new Matrix3f();
|
||||
private static final Matrix4f scratchMatrix = new Matrix4f();
|
||||
private static final Vector3f scratchCol = new Vector3f();
|
||||
|
||||
private static final float LIGHTMAP_SCALE = 1.0f / 256.0f;
|
||||
private static final FloatBuffer lightmapMatrixBuf;
|
||||
@@ -132,6 +134,16 @@ public class CompatUniformManager {
|
||||
|
||||
private CompatUniformManager() {}
|
||||
|
||||
/**
|
||||
* Normalize each column of a 3x3 matrix in place. Used to strip the residual 1/scale that
|
||||
* inverse-transpose introduces.
|
||||
*/
|
||||
private static void normalizeColumnsInPlace(Matrix3f m) {
|
||||
m.setColumn(0, m.getColumn(0, scratchCol).normalize());
|
||||
m.setColumn(1, m.getColumn(1, scratchCol).normalize());
|
||||
m.setColumn(2, m.getColumn(2, scratchCol).normalize());
|
||||
}
|
||||
|
||||
public static void onLinkProgram(int program) {
|
||||
int[] locs = new int[LOC_COUNT];
|
||||
boolean hasAny = false;
|
||||
@@ -222,13 +234,17 @@ public class CompatUniformManager {
|
||||
// Normal Matrix (inverse-transpose of upper-left 3x3 of ModelView)
|
||||
if (locs[LOC_NORMAL] != -1 || locs[LOC_IRIS_NORMAL] != -1) {
|
||||
mv.normal(normalMatrix);
|
||||
normalMatrix.get(mat3Buf);
|
||||
if (locs[LOC_NORMAL] != -1) {
|
||||
normalMatrix.get(mat3Buf);
|
||||
RENDER_BACKEND.uniformMatrix3(locs[LOC_NORMAL], false, mat3Buf);
|
||||
}
|
||||
// Column-normalized to unit magnitude
|
||||
if (locs[LOC_IRIS_NORMAL] != -1) {
|
||||
normalizeColumnsInPlace(normalMatrix);
|
||||
normalMatrix.get(mat3Buf);
|
||||
RENDER_BACKEND.uniformMatrix3(locs[LOC_IRIS_NORMAL], false, mat3Buf);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ public class FeedbackManager {
|
||||
final int byteCount = count * stride;
|
||||
ensureReadbackCapacity(byteCount);
|
||||
readbackBuf.clear().limit(byteCount);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, (long) first * stride + posOffset, readbackBuf);
|
||||
readPositionBuffer((long) first * stride + posOffset, readbackBuf);
|
||||
|
||||
emitAllPrimitives(mode, count, i -> i, stride);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class FeedbackManager {
|
||||
final int byteCount = vertexCount * stride;
|
||||
ensureReadbackCapacity(byteCount);
|
||||
readbackBuf.clear().limit(byteCount);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, (long) minIdx * stride + posOffset, readbackBuf);
|
||||
readPositionBuffer((long) minIdx * stride + posOffset, readbackBuf);
|
||||
|
||||
final int base = minIdx;
|
||||
emitAllPrimitives(mode, indexCount, i -> ImmediateModeRecorder.readIndex(indexBuf, type, 0, i) - base, stride);
|
||||
@@ -251,7 +251,23 @@ public class FeedbackManager {
|
||||
final int byteCount = vertexCount * stride;
|
||||
ensureReadbackCapacity(byteCount);
|
||||
readbackBuf.clear().limit(byteCount);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, (long) minIdx * stride + posOffset, readbackBuf);
|
||||
readPositionBuffer((long) minIdx * stride + posOffset, readbackBuf);
|
||||
}
|
||||
|
||||
private static void readPositionBuffer(long offset, ByteBuffer destination) {
|
||||
final int positionVbo = VertexAttribState.get(0).vboId;
|
||||
final int previousVbo = GLStateManager.getBoundVBO();
|
||||
|
||||
if (positionVbo != 0 && positionVbo != previousVbo) {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, positionVbo);
|
||||
}
|
||||
try {
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, offset, destination);
|
||||
} finally {
|
||||
if (positionVbo != 0 && positionVbo != previousVbo) {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, previousVbo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitVertex(int vertexIndex, int stride) {
|
||||
|
||||
@@ -163,18 +163,39 @@ public class GLStateManager {
|
||||
fragmentGeneration++;
|
||||
}
|
||||
|
||||
@Getter private static float shaderColorR = 1.0f;
|
||||
@Getter private static float shaderColorG = 1.0f;
|
||||
@Getter private static float shaderColorB = 1.0f;
|
||||
@Getter private static float shaderColorA = 1.0f;
|
||||
|
||||
public static void setShaderColor(float r, float g, float b, float a) {
|
||||
if (r == shaderColorR && g == shaderColorG && b == shaderColorB && a == shaderColorA) return;
|
||||
shaderColorR = r; shaderColorG = g; shaderColorB = b; shaderColorA = a;
|
||||
if (GLSMHooks.SHADER_COLOR_CHANGE.hasListeners()) {
|
||||
GLSMHooks.shaderColorChangeEvent.red = r;
|
||||
GLSMHooks.shaderColorChangeEvent.green = g;
|
||||
GLSMHooks.shaderColorChangeEvent.blue = b;
|
||||
GLSMHooks.shaderColorChangeEvent.alpha = a;
|
||||
GLSMHooks.SHADER_COLOR_CHANGE.post(GLSMHooks.shaderColorChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// Deferred vertex attribute upload flags — set when state changes, flushed before draw
|
||||
private static boolean dirtyColorAttrib;
|
||||
private static boolean dirtyColorAttrib = true;
|
||||
private static boolean dirtyNormalAttrib;
|
||||
private static boolean dirtyTexCoordAttrib;
|
||||
private static boolean dirtyLightmapAttrib;
|
||||
private static boolean dirtyLightmapAttrib = true;
|
||||
|
||||
/** Flush deferred vertex attribute uploads. Called before draw to ensure default attrib values are current. */
|
||||
public static void flushDeferredVertexAttribs() {
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.COLOR.getAttributeLocation(), color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
dirtyColorAttrib = false;
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.SECONDARY_UV.getAttributeLocation(), GLSMConfig.lastBrightnessX, GLSMConfig.lastBrightnessY, 0.0f, 1.0f);
|
||||
dirtyLightmapAttrib = false;
|
||||
if (dirtyColorAttrib) {
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.COLOR.getAttributeLocation(), color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
dirtyColorAttrib = false;
|
||||
}
|
||||
if (dirtyLightmapAttrib) {
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.SECONDARY_UV.getAttributeLocation(), GLSMConfig.lastBrightnessX, GLSMConfig.lastBrightnessY, 0.0f, 1.0f);
|
||||
dirtyLightmapAttrib = false;
|
||||
}
|
||||
if (dirtyNormalAttrib) {
|
||||
final var n = ShaderManager.getCurrentNormal();
|
||||
RENDER_BACKEND.vertexAttrib3f(Usage.NORMAL.getAttributeLocation(), n.x, n.y, n.z);
|
||||
|
||||
@@ -18,6 +18,7 @@ public final class GLSMHooks {
|
||||
public static final EventBus<FogStateChangeEvent> FOG_STATE_CHANGE = EventBus.create(FogStateChangeEvent.class);
|
||||
public static final EventBus<LightmapCoordsEvent> LIGHTMAP_COORDS = EventBus.create(LightmapCoordsEvent.class);
|
||||
public static final EventBus<AlphaStateChangeEvent> ALPHA_STATE_CHANGE = EventBus.create(AlphaStateChangeEvent.class);
|
||||
public static final EventBus<ShaderColorChangeEvent> SHADER_COLOR_CHANGE = EventBus.create(ShaderColorChangeEvent.class);
|
||||
|
||||
// Reusable event instances
|
||||
public static final TextureBindEvent textureBindEvent = new TextureBindEvent();
|
||||
@@ -28,6 +29,7 @@ public final class GLSMHooks {
|
||||
public static final FogStateChangeEvent fogStateChangeEvent = new FogStateChangeEvent();
|
||||
public static final LightmapCoordsEvent lightmapCoordsEvent = new LightmapCoordsEvent();
|
||||
public static final AlphaStateChangeEvent alphaStateChangeEvent = new AlphaStateChangeEvent();
|
||||
public static final ShaderColorChangeEvent shaderColorChangeEvent = new ShaderColorChangeEvent();
|
||||
|
||||
private GLSMHooks() {}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks.events;
|
||||
|
||||
import net.minecraftforge.eventbus.api.event.MutableEvent;
|
||||
|
||||
public final class ShaderColorChangeEvent extends MutableEvent {
|
||||
public float red;
|
||||
public float green;
|
||||
public float blue;
|
||||
public float alpha;
|
||||
}
|
||||
+8
-8
@@ -45,9 +45,9 @@ public class GLSM_TextureInfoCache_UnitTest {
|
||||
void testNonGenericUploadCachesWithoutRoundtrip() {
|
||||
int texId = GL11.glGenTextures();
|
||||
try {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(64 * 64 * 4);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
TextureInfo info = TextureInfoCache.INSTANCE.getInfo(texId);
|
||||
assertFalse(info.needsInternalFormatResolve());
|
||||
@@ -63,9 +63,9 @@ public class GLSM_TextureInfoCache_UnitTest {
|
||||
void testGenericCompressedPreservesAsPassedInternalFormat() {
|
||||
int texId = GL11.glGenTextures();
|
||||
try {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(64 * 64 * 4);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
TextureInfo info = TextureInfoCache.INSTANCE.getInfo(texId);
|
||||
assertEquals(GL13.GL_COMPRESSED_RGBA, info.getInternalFormat());
|
||||
@@ -80,15 +80,15 @@ public class GLSM_TextureInfoCache_UnitTest {
|
||||
void testRepeatedQueryAfterResolveUsesCache() {
|
||||
int texId = GL11.glGenTextures();
|
||||
try {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(64 * 64 * 4);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
TextureInfo info = TextureInfoCache.INSTANCE.getInfo(texId);
|
||||
assertTrue(info.needsInternalFormatResolve());
|
||||
int first = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
int first = GLStateManager.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
assertFalse(info.needsInternalFormatResolve());
|
||||
int second = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
int second = GLStateManager.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
assertEquals(first, second);
|
||||
} finally {
|
||||
GL11.glDeleteTextures(texId);
|
||||
|
||||
@@ -21,6 +21,8 @@ class SharedDrawableVaoTest {
|
||||
private static final String VERT_330 = "#version 330 core\nvoid main() { gl_Position = vec4(0.0); }\n";
|
||||
private static final String FRAG_330 = "#version 330 core\nout vec4 o;\nvoid main() { o = vec4(0.0); }\n";
|
||||
|
||||
private static boolean ownsDisplay = false;
|
||||
|
||||
@BeforeAll
|
||||
static void createContext() throws LWJGLException {
|
||||
assumeTrue(!Display.isCreated(), "inherited Display -- skipping to avoid profile drift");
|
||||
@@ -31,11 +33,13 @@ class SharedDrawableVaoTest {
|
||||
new PixelFormat().withDepthBits(24).withStencilBits(8),
|
||||
new ContextAttribs(4, 1).withProfileCore(true).withForwardCompatible(true));
|
||||
GL30.glBindVertexArray(GL30.glGenVertexArrays());
|
||||
ownsDisplay = true;
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void destroyContext() {
|
||||
if (Display.isCreated()) Display.destroy();
|
||||
if (ownsDisplay && Display.isCreated()) Display.destroy();
|
||||
ownsDisplay = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -560,6 +560,9 @@ public class BatchingFontRenderer {
|
||||
boolean curWave = false;
|
||||
boolean curDinnerbone = false;
|
||||
boolean curGradient = false;
|
||||
boolean curShadow = false;
|
||||
boolean curShadowCustomColor = false;
|
||||
int curShadowColorOverride = 0;
|
||||
int gradientStartRgb = 0, gradientEndRgb = 0;
|
||||
int gradientCharIndex = 0, gradientTotalChars = 0;
|
||||
float gradientStep = 0f;
|
||||
@@ -651,6 +654,19 @@ public class BatchingFontRenderer {
|
||||
curWave = !curWave;
|
||||
} else if (fmtCode == 'v' && AngelicaConfig.enableDinnerboneText) {
|
||||
curDinnerbone = !curDinnerbone;
|
||||
} else if (fmtCode == 'u' && AngelicaConfig.enableDropShadow) {
|
||||
int customRgb = (charIdx + SECTION_X_LENGTH < stringEnd)
|
||||
? ColorCodeUtils.parseSectionXAt(string, charIdx + 1)
|
||||
: -1;
|
||||
if (customRgb != -1) {
|
||||
curShadow = true;
|
||||
curShadowCustomColor = true;
|
||||
curShadowColorOverride = customRgb;
|
||||
charIdx += SECTION_X_LENGTH;
|
||||
} else {
|
||||
curShadow = !curShadow;
|
||||
if (!curShadow) curShadowCustomColor = false;
|
||||
}
|
||||
} else if (fmtCode == 'g' && AngelicaConfig.enableGradients && charIdx + GRADIENT_PAYLOAD < stringEnd) {
|
||||
int color1 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1);
|
||||
int color2 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1 + SECTION_X_LENGTH);
|
||||
@@ -674,6 +690,8 @@ public class BatchingFontRenderer {
|
||||
curWave = false;
|
||||
curDinnerbone = false;
|
||||
curGradient = false;
|
||||
curShadow = false;
|
||||
curShadowCustomColor = false;
|
||||
curColor = color;
|
||||
curShadowColor = shadowColor;
|
||||
}
|
||||
@@ -682,6 +700,8 @@ public class BatchingFontRenderer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == ColorCodeUtils.ESCAPED_AMPERSAND) { chr = '&'; }
|
||||
|
||||
if (FontConfig.enableCustomFont && FontConfig.enableGlyphReplacements) {
|
||||
final char replacement = GlyphReplacements.getReplacementGlyph(chr);
|
||||
if (replacement != 0) {
|
||||
@@ -747,13 +767,17 @@ public class BatchingFontRenderer {
|
||||
renderY += (float) Math.sin(visibleCharIndex * WAVE_FREQUENCY + time) * AngelicaConfig.waveAmplitude;
|
||||
}
|
||||
|
||||
if (enableShadow) {
|
||||
final boolean drawShadow = enableShadow || curShadow;
|
||||
if (drawShadow) {
|
||||
final int effectiveShadowColor = curShadowCustomColor
|
||||
? ((curColor & 0xFF000000) | (curShadowColorOverride & 0x00FFFFFF))
|
||||
: curShadowColor;
|
||||
for (int n = 1; n <= shadowCopies; n++) {
|
||||
final float shadowOffsetPart = shadowOffset * ((float) n / shadowCopies);
|
||||
pushTexRect(curX + shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
pushTexRect(curX + shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, effectiveShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
|
||||
if (curBold) {
|
||||
pushTexRect(curX + 2.0f * shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
pushTexRect(curX + 2.0f * shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, effectiveShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -775,7 +799,7 @@ public class BatchingFontRenderer {
|
||||
both: 4(1 + 2 * shadowCopies + boldCopies)
|
||||
*/
|
||||
int charCount = 1;
|
||||
if (enableShadow) { charCount += shadowCopies * (curBold ? 2 : 1); }
|
||||
if (drawShadow) { charCount += shadowCopies * (curBold ? 2 : 1); }
|
||||
if (curBold) { charCount += boldCopies; }
|
||||
final int vtxCount = 4 * charCount;
|
||||
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
|
||||
@@ -822,6 +846,7 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
|
||||
public float getCharWidthFine(char chr) {
|
||||
if (chr == ColorCodeUtils.ESCAPED_AMPERSAND) { chr = '&'; }
|
||||
if (chr == FORMATTING_CHAR) { return -1; }
|
||||
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
|
||||
@@ -18,6 +18,7 @@ public final class ColorCodeUtils {
|
||||
private ColorCodeUtils() {}
|
||||
|
||||
public static final char FORMATTING_CHAR = '§';
|
||||
public static final char ESCAPED_AMPERSAND = '';
|
||||
|
||||
public static final int SECTION_X_PAYLOAD = 12;
|
||||
public static final int SECTION_X_LENGTH = 14;
|
||||
@@ -25,7 +26,7 @@ public final class ColorCodeUtils {
|
||||
public static final int GRADIENT_LENGTH = 30;
|
||||
|
||||
/** Valid single {@code &} codes. {@code g} is excluded; {@code &g} only converts as part of a gradient. */
|
||||
public static final String VALID_SINGLE_CODES = "0123456789abcdefklmnorqzv";
|
||||
public static final String VALID_SINGLE_CODES = "0123456789abcdefklmnorqzvu";
|
||||
|
||||
private static final String[] SECTION_PREFIX = new String[128];
|
||||
static {
|
||||
@@ -87,6 +88,14 @@ public final class ColorCodeUtils {
|
||||
StringBuilder sb = null;
|
||||
int last = 0;
|
||||
while (idx != -1 && idx + 1 < len) {
|
||||
if (idx > 0 && text.charAt(idx - 1) == '\\') {
|
||||
if (sb == null) sb = new StringBuilder(len + 16);
|
||||
sb.append(text, last, idx - 1);
|
||||
sb.append(ESCAPED_AMPERSAND);
|
||||
last = idx + 1;
|
||||
idx = text.indexOf('&', last);
|
||||
continue;
|
||||
}
|
||||
if (text.charAt(idx + 1) == '#' && idx + 7 < len) {
|
||||
boolean validHex = true;
|
||||
for (int i = 2; i <= 7; i++) {
|
||||
|
||||
@@ -132,6 +132,10 @@ public class AngelicaConfig {
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean enableDinnerboneText;
|
||||
|
||||
@Config.Comment("Enable per-segment drop shadow toggle (&u) and colored shadow (&u&#RRGGBB)")
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean enableDropShadow;
|
||||
|
||||
@Config.Comment("Wave text amplitude (how far characters bounce)")
|
||||
@Config.DefaultFloat(2.0f)
|
||||
@Config.RangeFloat(min = 1.0f, max = 8.0f)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.gtnewhorizons.angelica.event;
|
||||
|
||||
import net.minecraftforge.eventbus.api.bus.EventBus;
|
||||
import net.minecraftforge.eventbus.api.event.MutableEvent;
|
||||
|
||||
public final class ChunkBiomeDataChangedEvent extends MutableEvent {
|
||||
|
||||
public static final EventBus<ChunkBiomeDataChangedEvent> BUS = EventBus.create(ChunkBiomeDataChangedEvent.class);
|
||||
|
||||
private static final ChunkBiomeDataChangedEvent INSTANCE = new ChunkBiomeDataChangedEvent();
|
||||
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
|
||||
public static void post(int chunkX, int chunkZ) {
|
||||
if (!BUS.hasListeners()) return;
|
||||
INSTANCE.chunkX = chunkX;
|
||||
INSTANCE.chunkZ = chunkZ;
|
||||
BUS.post(INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class IrisGLSMBridge {
|
||||
private static Runnable fogStartListener = null;
|
||||
private static Runnable fogEndListener = null;
|
||||
private static Runnable fogDensityListener = null;
|
||||
private static Runnable colorModulatorListener = null;
|
||||
|
||||
static {
|
||||
StateUpdateNotifiers.alphaFuncNotifier = listener -> alphaFuncListener = listener;
|
||||
@@ -35,6 +36,7 @@ public class IrisGLSMBridge {
|
||||
StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener;
|
||||
StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener;
|
||||
StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener;
|
||||
StateUpdateNotifiers.colorModulatorNotifier = listener -> colorModulatorListener = listener;
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
@@ -108,6 +110,10 @@ public class IrisGLSMBridge {
|
||||
}
|
||||
});
|
||||
|
||||
GLSMHooks.SHADER_COLOR_CHANGE.addListener(event -> {
|
||||
if (Iris.enabled && colorModulatorListener != null) colorModulatorListener.run();
|
||||
});
|
||||
|
||||
GLSMHooks.FOG_STATE_CHANGE.addListener(event -> {
|
||||
if (Iris.enabled) {
|
||||
if (fogModeListener != null) fogModeListener.run();
|
||||
@@ -157,17 +163,17 @@ public class IrisGLSMBridge {
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (event.postBind) return;
|
||||
|
||||
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
if (!(pipeline instanceof DeferredWorldRenderingPipeline drp)) return;
|
||||
if (!drp.shouldOverrideShaders()) return;
|
||||
if (drp.getActivePassProgramId() == -1) return;
|
||||
|
||||
|
||||
if (DepthColorStorage.isOwnedProgram(event.newProgram)) {
|
||||
DepthColorStorage.unlockDepthColor();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (!event.postBind) return;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
final class CloudEdges {
|
||||
private static final int CELL_EMPTY_THRESHOLD = 10;
|
||||
|
||||
final int width, height;
|
||||
private final int wMask, hMask;
|
||||
private final boolean whPow2;
|
||||
private final long[] opaqueBits;
|
||||
final int opaqueCount;
|
||||
|
||||
CloudEdges(int width, int height, ByteBuffer rgba) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.wMask = width - 1;
|
||||
this.hMask = height - 1;
|
||||
this.whPow2 = (width & wMask) == 0 && (height & hMask) == 0;
|
||||
final int total = width * height;
|
||||
final long[] bits = new long[(total + 63) >>> 6];
|
||||
int op = 0;
|
||||
for (int i = 0; i < total; i++) {
|
||||
if ((rgba.get(i * 4 + 3) & 0xFF) >= CELL_EMPTY_THRESHOLD) {
|
||||
bits[i >>> 6] |= 1L << (i & 63);
|
||||
op++;
|
||||
}
|
||||
}
|
||||
this.opaqueBits = bits;
|
||||
this.opaqueCount = op;
|
||||
}
|
||||
|
||||
boolean cellOpaque(int x, int z) {
|
||||
final int xw, zh;
|
||||
if (whPow2) {
|
||||
xw = x & wMask;
|
||||
zh = z & hMask;
|
||||
} else {
|
||||
xw = Math.floorMod(x, width);
|
||||
zh = Math.floorMod(z, height);
|
||||
}
|
||||
final int idx = xw + zh * width;
|
||||
return ((opaqueBits[idx >>> 6] >>> (idx & 63)) & 1L) != 0L;
|
||||
}
|
||||
|
||||
long readOpaqueRowBits(int x0, int z) {
|
||||
final int zMod, x0Mod;
|
||||
if (whPow2) {
|
||||
zMod = z & hMask;
|
||||
x0Mod = x0 & wMask;
|
||||
} else {
|
||||
zMod = Math.floorMod(z, height);
|
||||
x0Mod = Math.floorMod(x0, width);
|
||||
}
|
||||
if (x0Mod + 10 <= width) {
|
||||
return readContigBits(opaqueBits, (long) zMod * width + x0Mod, 10);
|
||||
}
|
||||
final int colsBeforeWrap = width - x0Mod;
|
||||
final long firstPart = readContigBits(opaqueBits, (long) zMod * width + x0Mod, colsBeforeWrap);
|
||||
final long secondPart = readContigBits(opaqueBits, (long) zMod * width, 10 - colsBeforeWrap);
|
||||
return firstPart | (secondPart << colsBeforeWrap);
|
||||
}
|
||||
|
||||
private static long readContigBits(long[] bits, long startBitIdx, int count) {
|
||||
final int wordIdx = (int) (startBitIdx >>> 6);
|
||||
final int bitOff = (int) (startBitIdx & 63);
|
||||
final long mask = count == 64 ? -1L : (1L << count) - 1L;
|
||||
final long w0 = bits[wordIdx];
|
||||
if (bitOff + count <= 64) {
|
||||
return (w0 >>> bitOff) & mask;
|
||||
}
|
||||
final long w1 = bits[wordIdx + 1];
|
||||
return ((w0 >>> bitOff) | (w1 << (64 - bitOff))) & mask;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,78 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderBindingContext;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat4v;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformInt;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformMatrix4f;
|
||||
|
||||
final class CloudUniforms {
|
||||
static final float ALPHA = 0.8f;
|
||||
|
||||
final GlUniformMatrix4f mvp;
|
||||
final GlUniformFloat4v colorMult;
|
||||
final GlUniformFloat4v fogParams;
|
||||
final GlUniformFloat4v fogColor;
|
||||
final GlUniformInt fogEnabled;
|
||||
final GlUniformInt tex;
|
||||
|
||||
private int lastFogEnabled = -1;
|
||||
private float lastFogR = Float.NaN, lastFogG = Float.NaN, lastFogB = Float.NaN;
|
||||
private float lastColorR = Float.NaN, lastColorG = Float.NaN, lastColorB = Float.NaN;
|
||||
private float lastFogParamX = Float.NaN, lastFogParamY = Float.NaN;
|
||||
private final float[] uploadBuf = new float[4];
|
||||
|
||||
CloudUniforms(ShaderBindingContext ctx) {
|
||||
mvp = ctx.bindUniform("u_MVPMatrix", GlUniformMatrix4f::new);
|
||||
colorMult = ctx.bindUniform("u_ColorMult", GlUniformFloat4v::new);
|
||||
fogParams = ctx.bindUniform("u_FogParams", GlUniformFloat4v::new);
|
||||
fogColor = ctx.bindUniform("u_FogColor", GlUniformFloat4v::new);
|
||||
fogEnabled = ctx.bindUniform("u_FogEnabled", GlUniformInt::new);
|
||||
tex = ctx.bindUniform("u_Tex", GlUniformInt::new);
|
||||
}
|
||||
|
||||
void setFogEnabled(boolean enabled) {
|
||||
final int val = enabled ? 1 : 0;
|
||||
if (val != lastFogEnabled) {
|
||||
lastFogEnabled = val;
|
||||
fogEnabled.setInt(val);
|
||||
}
|
||||
}
|
||||
|
||||
void setFogColor(float r, float g, float b) {
|
||||
if (r != lastFogR || g != lastFogG || b != lastFogB) {
|
||||
lastFogR = r;
|
||||
lastFogG = g;
|
||||
lastFogB = b;
|
||||
uploadBuf[0] = r;
|
||||
uploadBuf[1] = g;
|
||||
uploadBuf[2] = b;
|
||||
uploadBuf[3] = 1.0f;
|
||||
fogColor.set(uploadBuf);
|
||||
}
|
||||
}
|
||||
|
||||
void setFogParams(float x, float y) {
|
||||
if (x != lastFogParamX || y != lastFogParamY) {
|
||||
lastFogParamX = x;
|
||||
lastFogParamY = y;
|
||||
uploadBuf[0] = x;
|
||||
uploadBuf[1] = y;
|
||||
uploadBuf[2] = 0f;
|
||||
uploadBuf[3] = 0f;
|
||||
fogParams.set(uploadBuf);
|
||||
}
|
||||
}
|
||||
|
||||
void setColorMult(float r, float g, float b) {
|
||||
if (r != lastColorR || g != lastColorG || b != lastColorB) {
|
||||
lastColorR = r;
|
||||
lastColorG = g;
|
||||
lastColorB = b;
|
||||
uploadBuf[0] = r;
|
||||
uploadBuf[1] = g;
|
||||
uploadBuf[2] = b;
|
||||
uploadBuf[3] = ALPHA;
|
||||
colorMult.set(uploadBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -7,6 +7,8 @@ import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHold
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskProvider;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskRegistry;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ClonedChunkSectionCache;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
@@ -40,6 +42,7 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
|
||||
private final WorldClient world;
|
||||
private final ClonedChunkSectionCache sectionCache;
|
||||
private final ChunkTaskProvider taskProvider;
|
||||
private final LongOpenHashSet biomeRebuildColumns = new LongOpenHashSet();
|
||||
|
||||
public AngelicaRenderSectionManager(RenderPassConfiguration<?> configuration, WorldClient world, int renderDistance, CommandList commandList, int minSection, int maxSection, int requestedThreads, ChunkTaskProvider taskProvider) {
|
||||
super(configuration, () -> new AngelicaChunkBuildContext(configuration, world), AngelicaChunkRenderer::new, renderDistance, commandList, minSection, maxSection, requestedThreads, true /* hasShadowPass = true for Iris */);
|
||||
@@ -144,9 +147,35 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
|
||||
this.sectionCache.invalidate(section.getChunkX(), section.getChunkY(), section.getChunkZ());
|
||||
}
|
||||
|
||||
public void onBiomesChanged(int chunkX, int chunkZ) {
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
this.biomeRebuildColumns.add(PositionUtil.packChunk(chunkX + dx, chunkZ + dz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flushBiomeRebuilds() {
|
||||
if (this.biomeRebuildColumns.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final int sectionCountY = this.world.getHeight() >> 4;
|
||||
for (final LongIterator it = this.biomeRebuildColumns.iterator(); it.hasNext(); ) {
|
||||
final long column = it.nextLong();
|
||||
final int cx = PositionUtil.unpackChunkX(column);
|
||||
final int cz = PositionUtil.unpackChunkZ(column);
|
||||
for (int cy = 0; cy < sectionCountY; cy++) {
|
||||
this.sectionCache.invalidate(cx, cy, cz);
|
||||
this.scheduleRebuild(cx, cy, cz, false);
|
||||
}
|
||||
}
|
||||
this.biomeRebuildColumns.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChunks(boolean updateImmediately) {
|
||||
this.sectionCache.cleanup();
|
||||
this.flushBiomeRebuilds();
|
||||
super.updateChunks(updateImmediately);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.rendering.celeritas;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.event.ChunkBiomeDataChangedEvent;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
|
||||
import org.embeddedt.embeddium.impl.gl.device.GLRenderDevice;
|
||||
@@ -12,8 +13,16 @@ public class CeleritasSetup {
|
||||
public static void ensureInitialized() {
|
||||
if (!initialized && AngelicaConfig.enableCeleritas) {
|
||||
GLRenderDevice.VANILLA_STATE_RESETTER = () -> GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
ChunkBiomeDataChangedEvent.BUS.addListener(CeleritasSetup::onChunkBiomeDataChanged);
|
||||
AngelicaClientTweaker.LOGGER.debug("Celeritas init");
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void onChunkBiomeDataChanged(ChunkBiomeDataChangedEvent event) {
|
||||
final CeleritasWorldRenderer renderer = CeleritasWorldRenderer.getInstanceOrNull();
|
||||
if (renderer != null && renderer.isActive()) {
|
||||
renderer.getRenderSectionManager().onBiomesChanged(event.chunkX, event.chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -74,6 +74,10 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static CeleritasWorldRenderer getInstanceOrNull() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public AngelicaRenderSectionManager getRenderSectionManager() {
|
||||
return this.renderSectionManager;
|
||||
}
|
||||
@@ -118,7 +122,16 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
protected ChunkRenderMatrices createChunkRenderMatrices() {
|
||||
final boolean shadowPass = renderSectionManager.isInShadowPass();
|
||||
final Matrix4f projection = shadowPass ? ShadowRenderer.PROJECTION : RenderingState.INSTANCE.getProjectionMatrix();
|
||||
final Matrix4f modelView = shadowPass ? ShadowRenderer.MODELVIEW : RenderingState.INSTANCE.getModelViewMatrix();
|
||||
Matrix4f modelView = shadowPass ? ShadowRenderer.MODELVIEW : RenderingState.INSTANCE.getModelViewMatrix();
|
||||
if (!shadowPass) {
|
||||
// Minecraft's setupCameraTransform bakes translate(0, -eyeHeight, 0) into the modelview.
|
||||
// Chunk rendering passes eye position to drawChunkLayer so vertices arrive at
|
||||
// the shader as (vert_world - eye).
|
||||
final Entity view = mc.renderViewEntity;
|
||||
if (view != null) {
|
||||
modelView = new Matrix4f(modelView).translate(0f, view.getEyeHeight(), 0f);
|
||||
}
|
||||
}
|
||||
return new ChunkRenderMatrices(projection, modelView);
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -26,6 +26,11 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
private static final int NORMAL_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("iris_Normal").getPointer();
|
||||
private static final int MC_ENTITY_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("mc_Entity").getPointer();
|
||||
private static final int MID_BLOCK_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("at_midBlock").getPointer();
|
||||
private static final int A_TEXCOORD_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("a_TexCoord").getPointer();
|
||||
|
||||
// One unit of UV-space shift toward the quad centroid. Stops bilinear /
|
||||
// mipmap sampling from bleeding pixels from neighboring atlas cells.
|
||||
private static final float TEX_CENTROID_BIAS = 1.0f / 32768.0f;
|
||||
|
||||
private final ChunkVertexEncoder baseEncoder = IrisExtendedChunkVertexType.BASE_TYPE.createEncoder();
|
||||
private final CeleritasQuadView quad = new CeleritasQuadView();
|
||||
@@ -98,6 +103,14 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
memPutInt(ptr + MID_TEX_OFFSET - STRIDE * 2, midUV);
|
||||
memPutInt(ptr + MID_TEX_OFFSET - STRIDE * 3, midUV);
|
||||
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
final long uvBase = ptr - (long) (3 - vIdx) * STRIDE + A_TEXCOORD_OFFSET;
|
||||
final float vU = memGetFloat(uvBase);
|
||||
final float vV = memGetFloat(uvBase + 4L);
|
||||
memPutFloat(uvBase, vU + (vU < midU ? TEX_CENTROID_BIAS : -TEX_CENTROID_BIAS));
|
||||
memPutFloat(uvBase + 4L, vV + (vV < midV ? TEX_CENTROID_BIAS : -TEX_CENTROID_BIAS));
|
||||
}
|
||||
|
||||
quad.setup(ptr, STRIDE);
|
||||
NormalHelper.computeFaceNormal(normal, quad);
|
||||
final int packedNormal = NormI8.pack(normal);
|
||||
|
||||
+27
-26
@@ -1,6 +1,5 @@
|
||||
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;
|
||||
@@ -20,6 +19,7 @@ import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.biome.WorldChunkManager;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
@@ -62,50 +62,51 @@ public class ClonedChunkSection {
|
||||
this.pos = pos;
|
||||
this.data = new ExtendedBlockStorageExt(chunk, section);
|
||||
|
||||
final int bArrLength;
|
||||
if (ModStatus.isEIDBiomeLoaded) {
|
||||
bArrLength = ((ChunkBiomeHook) chunk).getBiomeShortArray().length;
|
||||
} else {
|
||||
bArrLength = chunk.getBiomeArray().length;
|
||||
}
|
||||
this.biomeData = new BiomeGenBase[bArrLength];
|
||||
this.biomeData = new BiomeGenBase[16 * 16];
|
||||
|
||||
copyBlockEntities(chunk, pos);
|
||||
|
||||
// Fill biome data
|
||||
for (int z = pos.getMinZ(); z <= pos.getMaxZ(); z++) {
|
||||
for (int x = pos.getMinX(); x <= pos.getMaxX(); x++) {
|
||||
this.biomeData[(x & 15) | ((z & 15) << 4)] = world.getBiomeGenForCoords(x, z);
|
||||
}
|
||||
}
|
||||
fillBiomeData(chunk);
|
||||
|
||||
this.sectionLightData = BlockLightProvider.getInstance().prepareSectionData(chunk, pos.y);
|
||||
}
|
||||
|
||||
private void fillBiomeData(Chunk chunk) {
|
||||
final WorldChunkManager wcm = world.getWorldChunkManager();
|
||||
for (int lz = 0; lz < 16; lz++) {
|
||||
for (int lx = 0; lx < 16; lx++) {
|
||||
this.biomeData[lx | (lz << 4)] = chunk.getBiomeGenForWorldCoords(lx, lz, wcm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void copyBlockEntities(Chunk chunk, ChunkSectionPos pos) {
|
||||
this.tileEntities.clear();
|
||||
|
||||
final ConcurrentTileEntityMap map = ((IChunkTileEntityMapHolder) chunk).angelica$getConcurrentTEMap();
|
||||
|
||||
map.withReadLock(() -> {
|
||||
map.readLock();
|
||||
try {
|
||||
final Object2ObjectOpenHashMap<ChunkPosition, TileEntity> delegate = map.getDelegate();
|
||||
|
||||
if (delegate.isEmpty()) return;
|
||||
if (!delegate.isEmpty()) {
|
||||
final int minY = pos.getMinY();
|
||||
final int maxY = pos.getMaxY();
|
||||
|
||||
final int minY = pos.getMinY();
|
||||
final int maxY = pos.getMaxY();
|
||||
for (Object2ObjectMap.Entry<ChunkPosition, TileEntity> entry : Object2ObjectMaps.fastIterable(delegate)) {
|
||||
final ChunkPosition tePos = entry.getKey();
|
||||
if (tePos.chunkPosY < minY || tePos.chunkPosY > maxY) continue;
|
||||
|
||||
for (Object2ObjectMap.Entry<ChunkPosition, TileEntity> entry : Object2ObjectMaps.fastIterable(delegate)) {
|
||||
final ChunkPosition tePos = entry.getKey();
|
||||
if (tePos.chunkPosY < minY || tePos.chunkPosY > maxY) continue;
|
||||
|
||||
final TileEntity te = entry.getValue();
|
||||
if (te != null && !te.isInvalid()) {
|
||||
this.tileEntities.put(ChunkSectionPos.packLocal(tePos.chunkPosX & 15, tePos.chunkPosY & 15, tePos.chunkPosZ & 15), te);
|
||||
final TileEntity te = entry.getValue();
|
||||
if (te != null && !te.isInvalid()) {
|
||||
this.tileEntities.put(ChunkSectionPos.packLocal(tePos.chunkPosX & 15, tePos.chunkPosY & 15, tePos.chunkPosZ & 15), te);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
map.readUnlock();
|
||||
}
|
||||
|
||||
this.tileEntities.trim();
|
||||
}
|
||||
|
||||
+11
-6
@@ -21,7 +21,13 @@ public class ClonedChunkSectionCache {
|
||||
|
||||
public synchronized void cleanup() {
|
||||
this.time = getMonotonicTimeSource();
|
||||
this.byPosition.values().removeIf(entry -> this.time > (entry.getLastUsedTimestamp() + MAX_CACHE_DURATION));
|
||||
while (!this.byPosition.isEmpty()) {
|
||||
final ClonedChunkSection oldest = this.byPosition.get(this.byPosition.firstLongKey());
|
||||
if (this.time <= oldest.getLastUsedTimestamp() + MAX_CACHE_DURATION) {
|
||||
break;
|
||||
}
|
||||
this.byPosition.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ClonedChunkSection acquire(int x, int y, int z) {
|
||||
@@ -32,18 +38,17 @@ public class ClonedChunkSectionCache {
|
||||
while (this.byPosition.size() >= MAX_CACHE_SIZE) {
|
||||
this.byPosition.removeFirst();
|
||||
}
|
||||
section = this.createSection(x, y, z);
|
||||
section = this.createSection(key, x, y, z);
|
||||
}
|
||||
|
||||
section.setLastUsedTimestamp(this.time);
|
||||
return section;
|
||||
}
|
||||
|
||||
private ClonedChunkSection createSection(int x, int y, int z) {
|
||||
private ClonedChunkSection createSection(long key, int x, int y, int z) {
|
||||
final ClonedChunkSection section = new ClonedChunkSection(this, this.world);
|
||||
final ChunkSectionPos pos = ChunkSectionPos.from(x, y, z);
|
||||
section.init(pos);
|
||||
this.byPosition.putAndMoveToLast(pos.asLong(), section);
|
||||
section.init(ChunkSectionPos.from(x, y, z));
|
||||
this.byPosition.putAndMoveToLast(key, section);
|
||||
return section;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,14 @@ public class ConcurrentTileEntityMap implements Map<ChunkPosition, TileEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
public void readLock() {
|
||||
lock.readLock().lock();
|
||||
}
|
||||
|
||||
public void readUnlock() {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
|
||||
public void withWriteLock(Runnable action) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
|
||||
@@ -540,56 +540,63 @@ public class SodiumGameOptionPages {
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("RGB Colors")
|
||||
.setTooltip("Enable hex colors via &#RRGGBB syntax")
|
||||
.setName(I18n.format("options.angelica.texteffects.rgb_colors"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.rgb_colors.tooltip", "\\&#RRGGBB"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableRGBColors = value,
|
||||
opts -> AngelicaConfig.enableRGBColors)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Gradients")
|
||||
.setTooltip("Smooth color transitions via &g&#start&#end")
|
||||
.setName(I18n.format("options.angelica.texteffects.gradients"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.gradients.tooltip") + " \\&g\\&#start\\&#end")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableGradients = value,
|
||||
opts -> AngelicaConfig.enableGradients)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Rainbow")
|
||||
.setTooltip("Cycling rainbow colors via &q")
|
||||
.setName(I18n.format("options.angelica.texteffects.rainbow"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.rainbow.tooltip") + " \\&q")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableRainbow = value,
|
||||
opts -> AngelicaConfig.enableRainbow)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Wave Text")
|
||||
.setTooltip("Animated bouncing text via &z")
|
||||
.setName(I18n.format("options.angelica.texteffects.wave_text"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.wave_text.tooltip") + " \\&z")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableWaveText = value,
|
||||
opts -> AngelicaConfig.enableWaveText)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(int.class, angelicaOpts)
|
||||
.setName("Wave Amplitude")
|
||||
.setTooltip("How far wave text bounces (default 2.0)")
|
||||
.setName(I18n.format("options.angelica.texteffects.wave_amplitude"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.wave_amplitude.tooltip"))
|
||||
.setControl(option -> new SliderControl(option, 10, 80, 5, v -> (v / 10) + "." + (v % 10)))
|
||||
.setBinding((opts, value) -> AngelicaConfig.waveAmplitude = value / 10f, opts -> Math.round(AngelicaConfig.waveAmplitude * 10f))
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Dinnerbone Text")
|
||||
.setTooltip("Flipped upside down text via &v")
|
||||
.setName(I18n.format("options.angelica.texteffects.dinnerbone_text"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.dinnerbone_text.tooltip") + " \\&v")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableDinnerboneText = value,
|
||||
opts -> AngelicaConfig.enableDinnerboneText)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Ampersand Conversion")
|
||||
.setTooltip("Convert & prefix codes to formatting codes at render time")
|
||||
.setName(I18n.format("options.angelica.texteffects.drop_shadow"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.drop_shadow.tooltip", "\\&u") + " \\&u\\&#RRGGBB")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableDropShadow = value,
|
||||
opts -> AngelicaConfig.enableDropShadow)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.texteffects.ampersand_conversion"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.ampersand_conversion.tooltip", "\\&"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableAmpersandConversion = value,
|
||||
opts -> AngelicaConfig.enableAmpersandConversion)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
return new OptionPage("Text Effects", ImmutableList.copyOf(groups));
|
||||
return new OptionPage(I18n.format("sodium.options.pages.text"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public enum RenderCondition {
|
||||
HAND_TRANSLUCENT,
|
||||
RAIN_SNOW,
|
||||
WORLD_BORDER,
|
||||
LIGHTNING,
|
||||
SHADOW_TRANSLUCENT,
|
||||
// NB: Must be last due to implementation details of DeferredWorldRenderingPipeline
|
||||
SHADOW
|
||||
|
||||
@@ -3,5 +3,6 @@ package net.coderbot.iris.gbuffer_overrides.matching;
|
||||
public enum SpecialCondition {
|
||||
ENTITY_EYES,
|
||||
BEACON_BEAM,
|
||||
GLINT
|
||||
GLINT,
|
||||
LIGHTNING
|
||||
}
|
||||
@@ -2,16 +2,16 @@ package net.coderbot.iris.gl.buffer;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import lombok.Getter;
|
||||
import org.embeddedt.embeddium.impl.gl.debug.GLDebug;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public class ShaderStorageBuffer {
|
||||
protected final int index;
|
||||
protected final ShaderStorageInfo info;
|
||||
protected int id;
|
||||
@Getter protected int id;
|
||||
|
||||
public ShaderStorageBuffer(int index, ShaderStorageInfo info) {
|
||||
this.id = RenderSystem.createBuffers();
|
||||
@@ -45,16 +45,13 @@ public class ShaderStorageBuffer {
|
||||
GLStateManager.glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, newId);
|
||||
|
||||
// Calculation time
|
||||
int newWidth = (int) (width * info.scaleX());
|
||||
int newHeight = (int) (height * info.scaleY());
|
||||
int finalSize = (newHeight * newWidth) * info.size();
|
||||
long newWidth = (long) (width * info.scaleX());
|
||||
long newHeight = (long) (height * info.scaleY());
|
||||
long finalSize = (newHeight * newWidth) * info.size();
|
||||
RenderSystem.bufferStorage(GL43.GL_SHADER_STORAGE_BUFFER, finalSize, 0);
|
||||
RenderSystem.clearBufferSubData(GL43.GL_SHADER_STORAGE_BUFFER, GL30.GL_R8, 0, finalSize, GL11.GL_RED, GL11.GL_BYTE, new int[]{0});
|
||||
RenderSystem.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, index, newId);
|
||||
id = newId;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.coderbot.iris.gl.buffer;
|
||||
|
||||
public record ShaderStorageInfo(int size, boolean relative, float scaleX, float scaleY) {
|
||||
public record ShaderStorageInfo(long size, boolean relative, float scaleX, float scaleY) {
|
||||
}
|
||||
@@ -4,15 +4,18 @@ import lombok.Getter;
|
||||
import net.coderbot.iris.gl.GlResource;
|
||||
import net.coderbot.iris.gl.blending.DepthColorStorage;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public final class Program extends GlResource {
|
||||
|
||||
|
||||
@Getter
|
||||
private final ProgramUniforms uniforms;
|
||||
|
||||
|
||||
@Getter
|
||||
private final ProgramSamplers samplers;
|
||||
|
||||
|
||||
@Getter
|
||||
private final ProgramImages images;
|
||||
|
||||
@@ -25,15 +28,16 @@ public final class Program extends GlResource {
|
||||
|
||||
DepthColorStorage.registerOwnedProgram(program);
|
||||
}
|
||||
|
||||
|
||||
public void use() {
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
GLStateManager.glUseProgram(getGlId());
|
||||
|
||||
|
||||
uniforms.update();
|
||||
samplers.update();
|
||||
images.update();
|
||||
}
|
||||
|
||||
|
||||
public static void unbind() {
|
||||
ProgramUniforms.clearActiveUniforms();
|
||||
ProgramSamplers.clearActiveSamplers();
|
||||
@@ -45,7 +49,7 @@ public final class Program extends GlResource {
|
||||
DepthColorStorage.unregisterOwnedProgram(getGlId());
|
||||
GLStateManager.glDeleteProgram(getGlId());
|
||||
}
|
||||
|
||||
|
||||
public int getProgramId() {
|
||||
return getGlId();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ 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;
|
||||
import net.coderbot.iris.shaderpack.IrisLimits;
|
||||
import net.coderbot.iris.shaderpack.StringPair;
|
||||
import net.coderbot.iris.texture.format.TextureFormat;
|
||||
import net.coderbot.iris.texture.format.TextureFormatLoader;
|
||||
@@ -81,6 +82,9 @@ public class StandardMacros {
|
||||
define(standardDefines, "IS_ANGELICA");
|
||||
if (AngelicaConfig.defineIsIris) {
|
||||
define(standardDefines, "IS_IRIS");
|
||||
define(standardDefines, "IRIS_VERSION", "10803");
|
||||
define(standardDefines, "IRIS_HAS_TRANSLUCENCY_SORTING");
|
||||
define(standardDefines, "MAX_COLOR_BUFFERS", String.valueOf(IrisLimits.MAX_COLOR_BUFFERS));
|
||||
}
|
||||
|
||||
if (DHCompat.hasRenderingEnabled()) {
|
||||
|
||||
@@ -11,6 +11,7 @@ public class StateUpdateNotifiers {
|
||||
public static ValueUpdateNotifier alphaFuncNotifier;
|
||||
public static ValueUpdateNotifier alphaTestNotifier;
|
||||
public static ValueUpdateNotifier blendFuncNotifier;
|
||||
public static ValueUpdateNotifier colorModulatorNotifier;
|
||||
public static ValueUpdateNotifier bindTextureNotifier;
|
||||
public static ValueUpdateNotifier normalTextureChangeNotifier;
|
||||
public static ValueUpdateNotifier specularTextureChangeNotifier;
|
||||
|
||||
@@ -90,6 +90,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -394,6 +395,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
null, null, ProgramId.Weather,
|
||||
// world border uses textured_lit even though it has no lightmap :/
|
||||
null, ProgramId.TexturedLit, ProgramId.TexturedLit,
|
||||
ProgramId.Lightning, ProgramId.Lightning, ProgramId.Lightning,
|
||||
ProgramId.ShadowWater, ProgramId.ShadowWater, ProgramId.ShadowWater,
|
||||
ProgramId.Shadow, ProgramId.Shadow, ProgramId.Shadow
|
||||
};
|
||||
@@ -517,7 +519,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
if (hasSetup) {
|
||||
ComputeProgram.unbind();
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
// Terrain pipeline sampler/image factory setup follows.
|
||||
@@ -723,6 +725,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
return RenderCondition.ENTITY_EYES;
|
||||
} else if (special == SpecialCondition.GLINT) {
|
||||
return RenderCondition.GLINT;
|
||||
} else if (special == SpecialCondition.LIGHTNING) {
|
||||
return RenderCondition.LIGHTNING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,11 +775,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
public boolean shouldOverrideShaders() {
|
||||
return isRenderingWorld && !isRenderingFullScreenPass && !isPostChain && isMainBound;
|
||||
}
|
||||
|
||||
|
||||
public Pass getActivePassProgram() {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public int getActivePassProgramId() {
|
||||
if (current == null) return -1;
|
||||
final Program p = current.getProgram();
|
||||
@@ -793,10 +797,10 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
if (!isRenderingWorld || isRenderingFullScreenPass || isPostChain || !isMainBound) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final RenderCondition condition = getCondition(getPhase());
|
||||
final Pass matched = table.match(condition, inputs);
|
||||
|
||||
|
||||
beginPass(matched);
|
||||
}
|
||||
|
||||
@@ -1332,7 +1336,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
if (ranSetup) {
|
||||
ComputeProgram.unbind();
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class AttributeTransformer {
|
||||
transformer.injectVariable("layout(location = 4) in vec3 iris_Normal;");
|
||||
|
||||
transformer.rename("gl_Vertex", "iris_Vertex");
|
||||
transformer.rename("gl_Color", "iris_Color");
|
||||
transformer.replaceExpression("gl_Color", "(iris_Color * iris_ColorModulator)");
|
||||
transformer.rename("gl_Normal", "iris_Normal");
|
||||
|
||||
// ftransform() = gl_ModelViewProjectionMatrix * gl_Vertex
|
||||
|
||||
@@ -34,6 +34,7 @@ class CeleritasTransformer {
|
||||
transformer.injectFunction(
|
||||
"void _celeritas_init() { " +
|
||||
"_vert_init(); " +
|
||||
"_vert_color = _vert_color * iris_ColorModulator; " +
|
||||
"iris_LightTexCoord = vec4(vec2(_vert_tex_light_coord), 0.0, 1.0); }");
|
||||
transformer.prependMain("_celeritas_init();");
|
||||
transformShared(transformer, parameters);
|
||||
@@ -60,6 +61,7 @@ class CeleritasTransformer {
|
||||
}
|
||||
|
||||
private static void transformShared(Transformer transformer, Parameters parameters) {
|
||||
transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)");
|
||||
CoreTransformHelper.injectMatrixUniforms(transformer);
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,10 @@ public class CommonTransformer {
|
||||
}
|
||||
|
||||
if (parameters.type == ShaderType.VERTEX) {
|
||||
root.injectVariable("uniform vec4 iris_ColorModulator;");
|
||||
root.injectVariable("out vec4 iris_FrontColor;");
|
||||
root.rename("gl_FrontColor", "iris_FrontColor");
|
||||
root.prependMain("iris_FrontColor = vec4(1.0);");
|
||||
root.prependMain("iris_FrontColor = iris_ColorModulator;");
|
||||
} else if (parameters.type == ShaderType.FRAGMENT) {
|
||||
root.injectVariable("in vec4 iris_FrontColor;");
|
||||
root.rename("gl_Color", "iris_FrontColor");
|
||||
|
||||
@@ -94,7 +94,7 @@ public class DHGenericTransformer {
|
||||
+ " float skyLight = (float(uSkyLight) + 0.5) / 16.0;"
|
||||
+ " _vert_tex_light_coord = vec2(blockLight, skyLight);"
|
||||
+ " dhMaterialId = aMaterial;"
|
||||
+ " _vert_color = iris_color;"
|
||||
+ " _vert_color = iris_color * iris_ColorModulator;"
|
||||
+ " }"
|
||||
);
|
||||
transformer.prependMain("_vert_init();");
|
||||
|
||||
@@ -86,7 +86,7 @@ public class DHTerrainTransformer {
|
||||
+ " _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;"
|
||||
+ " _vert_color = iris_color * iris_ColorModulator;"
|
||||
+ " }"
|
||||
);
|
||||
transformer.prependMain("_vert_init();");
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -263,7 +264,7 @@ public class CompositeRenderer {
|
||||
}
|
||||
|
||||
if (ranCompute) {
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
Program.unbind();
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -229,7 +230,7 @@ public class FinalPassRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
|
||||
if (!finalPass.mipmappedBuffers.isEmpty()) {
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
|
||||
@@ -41,6 +41,7 @@ public class ProgramSet {
|
||||
private final ProgramSource gbuffersEntities;
|
||||
private final ProgramSource gbuffersEntitiesTrans;
|
||||
private final ProgramSource gbuffersEntitiesGlowing;
|
||||
private final ProgramSource gbuffersLightning;
|
||||
private final ProgramSource gbuffersGlint;
|
||||
private final ProgramSource gbuffersEntityEyes;
|
||||
private final ProgramSource gbuffersBlock;
|
||||
@@ -120,6 +121,7 @@ public class ProgramSet {
|
||||
this.gbuffersEntities = readProgramSource(directory, sourceProvider, "gbuffers_entities", this, shaderProperties);
|
||||
this.gbuffersEntitiesTrans = readProgramSource(directory, sourceProvider, "gbuffers_entities_translucent", this, shaderProperties);
|
||||
this.gbuffersEntitiesGlowing = readProgramSource(directory, sourceProvider, "gbuffers_entities_glowing", this, shaderProperties);
|
||||
this.gbuffersLightning = readProgramSource(directory, sourceProvider, "gbuffers_lightning", this, shaderProperties);
|
||||
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);
|
||||
@@ -229,7 +231,7 @@ public class ProgramSet {
|
||||
programs.addAll (Arrays.asList(
|
||||
gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain,
|
||||
gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather,
|
||||
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans,
|
||||
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersLightning, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans,
|
||||
gbuffersHand, dhShadow, dhTerrain, dhGeneric, dhWater
|
||||
));
|
||||
|
||||
@@ -382,6 +384,10 @@ public class ProgramSet {
|
||||
return gbuffersEntitiesGlowing.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersLightning() {
|
||||
return gbuffersLightning.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersGlint() {
|
||||
return gbuffersGlint.requireValid();
|
||||
}
|
||||
@@ -437,6 +443,7 @@ public class ProgramSet {
|
||||
case Entities -> getGbuffersEntities();
|
||||
case EntitiesTrans -> getGbuffersEntitiesTrans();
|
||||
case EntitiesGlowing -> getGbuffersEntitiesGlowing();
|
||||
case Lightning -> getGbuffersLightning();
|
||||
case ArmorGlint -> getGbuffersGlint();
|
||||
case SpiderEyes -> getGbuffersEntityEyes();
|
||||
case Hand -> getGbuffersHand();
|
||||
|
||||
@@ -771,7 +771,7 @@ public class ShaderProperties {
|
||||
return;
|
||||
}
|
||||
|
||||
final int size = Integer.parseInt(parts[0]);
|
||||
final long size = Long.parseLong(parts[0]);
|
||||
|
||||
// Size < 1 means the shader dev intended to disable the buffer
|
||||
if (size < 1) {
|
||||
|
||||
@@ -23,7 +23,7 @@ public enum ProgramId {
|
||||
TexturedLit(ProgramGroup.Gbuffers, "textured_lit", Textured),
|
||||
SkyBasic(ProgramGroup.Gbuffers, "skybasic", Basic),
|
||||
SkyTextured(ProgramGroup.Gbuffers, "skytextured", Textured),
|
||||
Clouds(ProgramGroup.Gbuffers, "clouds", Textured),
|
||||
Clouds(ProgramGroup.Gbuffers, "clouds", Textured, null, new AlphaTestOverride(new AlphaTest(AlphaTestFunction.GREATER, 0.1F))),
|
||||
|
||||
Terrain(ProgramGroup.Gbuffers, "terrain", TexturedLit),
|
||||
TerrainSolid(ProgramGroup.Gbuffers, "terrain_solid", Terrain),
|
||||
@@ -39,6 +39,7 @@ public enum ProgramId {
|
||||
Entities(ProgramGroup.Gbuffers, "entities", TexturedLit),
|
||||
EntitiesTrans(ProgramGroup.Gbuffers, "entities_translucent", Entities),
|
||||
EntitiesGlowing(ProgramGroup.Gbuffers, "entities_glowing", Entities),
|
||||
Lightning(ProgramGroup.Gbuffers, "lightning", Entities),
|
||||
ArmorGlint(ProgramGroup.Gbuffers, "armor_glint", Textured),
|
||||
SpiderEyes(ProgramGroup.Gbuffers, "spidereyes", Textured,
|
||||
new BlendModeOverride(new BlendState(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE)),
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -208,7 +209,7 @@ public class ShadowCompositeRenderer {
|
||||
|
||||
if (ranCompute) {
|
||||
// Memory barrier for shader image access and texture fetch
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
Program.unbind();
|
||||
|
||||
@@ -89,7 +89,7 @@ public class CameraUniforms {
|
||||
|
||||
private void update() {
|
||||
previousCameraPosition.set(currentCameraPosition);
|
||||
previousCameraPositionUnshifted = currentCameraPositionUnshifted;
|
||||
previousCameraPositionUnshifted.set(currentCameraPositionUnshifted);
|
||||
currentCameraPosition.set(getUnshiftedCameraPosition()).add(shift);
|
||||
currentCameraPositionUnshifted.set(getUnshiftedCameraPosition());
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ public final class EntityIdHelper {
|
||||
private EntityIdHelper() {
|
||||
}
|
||||
|
||||
public static boolean isLightningBolt(Entity entity) {
|
||||
return entity instanceof EntityLightningBolt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity ID for the given entity.
|
||||
*
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.coderbot.iris.uniforms;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
|
||||
import com.gtnewhorizons.angelica.render.CloudRenderer;
|
||||
import net.coderbot.iris.gl.uniform.UniformHolder;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -40,6 +41,16 @@ public class IrisExclusiveUniforms {
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "eyePosition", IrisExclusiveUniforms::getEyePosition);
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "relativeEyePosition", IrisExclusiveUniforms::getRelativeEyePosition);
|
||||
uniforms.uniform4f(UniformUpdateFrequency.PER_TICK, "lightningBoltPosition", IrisExclusiveUniforms::getLightningBoltPosition);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "cloudTime", IrisExclusiveUniforms::getCloudTime);
|
||||
}
|
||||
|
||||
private static float getCloudTime() {
|
||||
final WorldClient level = Minecraft.getMinecraft().theWorld;
|
||||
if (level == null) return 0f;
|
||||
final long cycle = (long) CloudRenderer.getCloudTextureWidth() * 400L * CloudRenderer.getScaleMult();
|
||||
final long t = level.getTotalWorldTime() % cycle;
|
||||
final float partial = Minecraft.getMinecraft().timer.renderPartialTicks;
|
||||
return (t + partial) * 0.03F;
|
||||
}
|
||||
|
||||
private static float getThunderStrength() {
|
||||
|
||||
@@ -12,10 +12,19 @@ import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME;
|
||||
|
||||
public class IrisInternalUniforms {
|
||||
private static final Vector4f FOG_COLOR = new Vector4f();
|
||||
private static final Vector4f COLOR_MODULATOR = new Vector4f(1f, 1f, 1f, 1f);
|
||||
|
||||
private IrisInternalUniforms() {
|
||||
}
|
||||
|
||||
private static Vector4f getColorModulator() {
|
||||
return COLOR_MODULATOR.set(
|
||||
GLStateManager.getShaderColorR(),
|
||||
GLStateManager.getShaderColorG(),
|
||||
GLStateManager.getShaderColorB(),
|
||||
GLStateManager.getShaderColorA());
|
||||
}
|
||||
|
||||
private static float getEffectiveAlphaRef() {
|
||||
if (!GLStateManager.getAlphaTest().isEnabled() || GLStateManager.getAlphaState().getFunction() == GL11.GL_ALWAYS) {
|
||||
return -1.0f;
|
||||
@@ -44,5 +53,7 @@ public class IrisInternalUniforms {
|
||||
.uniform1f("iris_currentAlphaTest", IrisInternalUniforms::getEffectiveAlphaRef, StateUpdateNotifiers.alphaTestNotifier)
|
||||
.uniform1f("alphaTestRef", IrisInternalUniforms::getEffectiveAlphaRef, StateUpdateNotifiers.alphaTestNotifier)
|
||||
.uniform1i("iris_currentAlphaFunc", IrisInternalUniforms::getEffectiveAlphaFunc, StateUpdateNotifiers.alphaFuncNotifier);
|
||||
|
||||
uniforms.uniform4f("iris_ColorModulator", IrisInternalUniforms::getColorModulator, StateUpdateNotifiers.colorModulatorNotifier);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ 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 net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
@@ -17,8 +19,18 @@ public final class MatrixUniforms {
|
||||
private MatrixUniforms() {
|
||||
}
|
||||
|
||||
private static final Matrix4f GBUFFER_MODELVIEW_SCRATCH = new Matrix4f();
|
||||
private static Matrix4fc getGbufferModelView() {
|
||||
final Matrix4fc raw = RenderingState.INSTANCE.getModelViewMatrix();
|
||||
final Entity view = Minecraft.getMinecraft().renderViewEntity;
|
||||
if (view == null) {
|
||||
return raw;
|
||||
}
|
||||
return GBUFFER_MODELVIEW_SCRATCH.set(raw).translate(0f, view.getEyeHeight(), 0f);
|
||||
}
|
||||
|
||||
public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives directives) {
|
||||
addMatrix(uniforms, "ModelView", RenderingState.INSTANCE::getModelViewMatrix);
|
||||
addMatrix(uniforms, "ModelView", MatrixUniforms::getGbufferModelView);
|
||||
// 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);
|
||||
|
||||
@@ -14,6 +14,7 @@ sodium.options.pages.quality=Quality
|
||||
sodium.options.pages.performance=Performance
|
||||
sodium.options.pages.advanced=Advanced
|
||||
sodium.options.pages.appearance=Appearance
|
||||
sodium.options.pages.text=Text Effects
|
||||
sodium.options.view_distance.tooltip=The render distance controls how far away terrain will be rendered. Shorter distances mean that less terrain will be rendered, improving frame rates.
|
||||
sodium.options.simulation_distance.tooltip=The simulation distance controls how far away terrain and entities will be loaded and ticked. Shorter distances can reduce the internal server's load and may improve frame rates.
|
||||
sodium.options.brightness.tooltip=Controls the brightness (gamma) of the game.
|
||||
@@ -223,6 +224,22 @@ options.angelica.aggressiveChunkLoading=Aggressive Chunk Loading
|
||||
options.angelica.aggressiveChunkLoading.tooltip=Renders chunks immediately when loaded, even if neighbors aren't ready yet. Improves perceived loading speed at render distance edges. Chunks rebuild automatically when neighbors load. Useful for low render distance servers.
|
||||
options.angelica.disablef3=Disable F3 Additions
|
||||
options.angelica.disablef3.tooltip=Disables Angelica's additions to the F3 debug screen.
|
||||
options.angelica.texteffects.rgb_colors=RGB Colors
|
||||
options.angelica.texteffects.rgb_colors.tooltip=Enable hex colors via %s syntax
|
||||
options.angelica.texteffects.gradients=Gradients
|
||||
options.angelica.texteffects.gradients.tooltip=Smooth color transitions via
|
||||
options.angelica.texteffects.rainbow=Rainbow
|
||||
options.angelica.texteffects.rainbow.tooltip=Cycling rainbow colors via
|
||||
options.angelica.texteffects.wave_text=Wave Text
|
||||
options.angelica.texteffects.wave_text.tooltip=Animated bouncing text via
|
||||
options.angelica.texteffects.wave_amplitude=Wave Amplitude
|
||||
options.angelica.texteffects.wave_amplitude.tooltip=How far wave text bounces (default 2.0)
|
||||
options.angelica.texteffects.dinnerbone_text=Dinnerbone Text
|
||||
options.angelica.texteffects.dinnerbone_text.tooltip=Flipped upside down text via
|
||||
options.angelica.texteffects.drop_shadow=Drop Shadow
|
||||
options.angelica.texteffects.drop_shadow.tooltip=Per-segment drop shadow via %s, colored shadow via
|
||||
options.angelica.texteffects.ampersand_conversion=Ampersand Conversion
|
||||
options.angelica.texteffects.ampersand_conversion.tooltip=Convert %s prefix codes to formatting codes at render time
|
||||
|
||||
sodium.options.multidraw_mode.name=Multi-Draw Mode
|
||||
sodium.options.multidraw_mode.tooltip=Controls how draw commands are dispatched for terrain rendering. §lDirect§r uses glMultiDrawElementsBaseVertex (default, GL 3.2+). §lIndirect§r uses GPU indirect rendering (GL 4.3+), may reduce CPU overhead on some hardware. §lIndividual§r issues individual draw calls.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#version 330 core
|
||||
|
||||
in vec4 v_Color;
|
||||
in vec2 v_TexCoord0;
|
||||
in vec2 v_UV;
|
||||
in float v_FogCoord;
|
||||
in float v_Factor;
|
||||
|
||||
uniform sampler2D u_CloudTexture;
|
||||
uniform vec3 u_ColorMultiplier;
|
||||
uniform sampler2D u_Tex;
|
||||
uniform vec4 u_ColorMult;
|
||||
uniform vec4 u_FogParams; // x: -1/(end-start), y: end/(end-start)
|
||||
uniform vec4 u_FogColor;
|
||||
uniform bool u_FogEnabled;
|
||||
@@ -13,11 +13,10 @@ uniform bool u_FogEnabled;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 texColor = texture(u_CloudTexture, v_TexCoord0);
|
||||
vec4 color = v_Color * texColor;
|
||||
color.rgb *= u_ColorMultiplier;
|
||||
|
||||
if (color.a < 0.1) discard;
|
||||
vec4 texel = texture(u_Tex, v_UV);
|
||||
if (texel.a < 0.1) discard;
|
||||
vec4 color = texel * u_ColorMult;
|
||||
color.rgb *= v_Factor;
|
||||
|
||||
if (u_FogEnabled) {
|
||||
float f = clamp(v_FogCoord * u_FogParams.x + u_FogParams.y, 0.0, 1.0);
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec4 a_Color;
|
||||
layout(location = 2) in vec2 a_TexCoord0;
|
||||
layout(location = 2) in vec2 a_UV;
|
||||
layout(location = 5) in float a_Factor;
|
||||
|
||||
uniform mat4 u_MVPMatrix;
|
||||
uniform vec2 u_TexOffset;
|
||||
uniform vec2 u_FogOrigin;
|
||||
|
||||
out vec4 v_Color;
|
||||
out vec2 v_TexCoord0;
|
||||
out vec2 v_UV;
|
||||
out float v_FogCoord;
|
||||
out float v_Factor;
|
||||
|
||||
void main() {
|
||||
vec4 pos4 = vec4(a_Position, 1.0);
|
||||
gl_Position = u_MVPMatrix * pos4;
|
||||
v_Color = a_Color;
|
||||
v_TexCoord0 = a_TexCoord0 + u_TexOffset;
|
||||
vec2 horizDelta = a_Position.xz - u_FogOrigin;
|
||||
v_FogCoord = length(horizDelta);
|
||||
gl_Position = u_MVPMatrix * vec4(a_Position, 1.0);
|
||||
v_UV = a_UV;
|
||||
v_FogCoord = length(a_Position.xz);
|
||||
v_Factor = a_Factor;
|
||||
}
|
||||
+17
-1
@@ -3,6 +3,7 @@ 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.coderbot.iris.pipeline.ShadowRenderer;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -26,6 +27,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
* 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.
|
||||
*
|
||||
* For the shadow pass, all stencil operations are skipped. Shadow FBOs have no stencil attachment.
|
||||
* On AMD Windows, glClear(GL_STENCIL_BUFFER_BIT) on a depth-only FBO causes the driver to
|
||||
* promote it to GL_DEPTH24_STENCIL8 internally, corrupting depth values and breaking shadows.
|
||||
* Someone needs to yell at AMD to fix this decade old bug.
|
||||
*/
|
||||
@Mixin(value = ItemRenderer.class, priority = 1100)
|
||||
public class MixinItemRenderer_EdgeDepth {
|
||||
@@ -41,6 +47,7 @@ public class MixinItemRenderer_EdgeDepth {
|
||||
remap = false
|
||||
)
|
||||
private void angelica$stencilWriteStart(CallbackInfo ci) {
|
||||
if (ShadowRenderer.ACTIVE) return;
|
||||
GLStateManager.glEnable(GL11.GL_STENCIL_TEST);
|
||||
GLStateManager.glStencilMask(0x03);
|
||||
GLStateManager.glClearStencil(0);
|
||||
@@ -55,6 +62,7 @@ public class MixinItemRenderer_EdgeDepth {
|
||||
remap = false
|
||||
)
|
||||
private void angelica$stencilWriteEnd(CallbackInfo ci) {
|
||||
if (ShadowRenderer.ACTIVE) return;
|
||||
GLStateManager.glStencilMask(0x00);
|
||||
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
|
||||
}
|
||||
@@ -67,6 +75,10 @@ public class MixinItemRenderer_EdgeDepth {
|
||||
remap = false
|
||||
)
|
||||
private void angelica$glintStart(int func) {
|
||||
if (ShadowRenderer.ACTIVE) {
|
||||
GLStateManager.glDepthFunc(func);
|
||||
return;
|
||||
}
|
||||
angelica$glintMode = true;
|
||||
GLStateManager.glEnable(GL11.GL_STENCIL_TEST);
|
||||
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0x03);
|
||||
@@ -79,6 +91,10 @@ public class MixinItemRenderer_EdgeDepth {
|
||||
remap = false
|
||||
)
|
||||
private void angelica$glintEnd(int func) {
|
||||
if (ShadowRenderer.ACTIVE) {
|
||||
GLStateManager.glDepthFunc(func);
|
||||
return;
|
||||
}
|
||||
angelica$glintMode = false;
|
||||
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
|
||||
GLStateManager.glDepthMask(true);
|
||||
@@ -91,7 +107,7 @@ public class MixinItemRenderer_EdgeDepth {
|
||||
@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) {
|
||||
if (ShadowRenderer.ACTIVE || !angelica$glintMode || angelica$inPrepass) {
|
||||
original.call(tess, minU, minV, maxU, maxV, w, h, thickness);
|
||||
return;
|
||||
}
|
||||
|
||||
+11
@@ -292,6 +292,17 @@ public abstract class MixinFontRenderer implements FontRendererAccessor, IFontPa
|
||||
} else if (code >= 'k' && code <= 'o') {
|
||||
styles.append(ColorCodeUtils.sectionPrefix(code));
|
||||
i++;
|
||||
} else if (code == 'u') {
|
||||
if (i + 2 + SECTION_X_LENGTH <= len && ColorCodeUtils.isValidSectionX(text, i + 2)) {
|
||||
final StringBuilder cb = EXTRACT_COLOR;
|
||||
cb.setLength(0);
|
||||
for (int j = 0; j < 2 + SECTION_X_LENGTH; j++) cb.append(text.charAt(i + j));
|
||||
effects.append(cb);
|
||||
i += 1 + SECTION_X_LENGTH;
|
||||
} else {
|
||||
effects.append(ColorCodeUtils.sectionPrefix(code));
|
||||
i++;
|
||||
}
|
||||
} else if (code == 'q' || code == 'z' || code == 'v') {
|
||||
effects.append(ColorCodeUtils.sectionPrefix(code));
|
||||
i++;
|
||||
|
||||
+36
@@ -2,6 +2,8 @@ package com.gtnewhorizons.angelica.mixins.early.celeritas.terrain;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.hash.Fnv1a64;
|
||||
import com.gtnewhorizons.angelica.event.ChunkBiomeDataChangedEvent;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IChunkTileEntityMapHolder;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderThreadContext;
|
||||
import com.gtnewhorizons.angelica.utils.ConcurrentTileEntityMap;
|
||||
@@ -9,12 +11,15 @@ import net.minecraft.block.Block;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.biome.WorldChunkManager;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
@@ -31,6 +36,11 @@ public abstract class MixinChunk implements IChunkTileEntityMapHolder {
|
||||
|
||||
@Shadow public abstract void addTileEntity(TileEntity te);
|
||||
|
||||
@Shadow public abstract BiomeGenBase getBiomeGenForWorldCoords(int x, int z, WorldChunkManager wcm);
|
||||
|
||||
@Unique private long angelica$biomeHash;
|
||||
@Unique private boolean angelica$biomeHashValid;
|
||||
|
||||
@Override
|
||||
public ConcurrentTileEntityMap angelica$getConcurrentTEMap() {
|
||||
return (ConcurrentTileEntityMap) this.chunkTileEntityMap;
|
||||
@@ -116,4 +126,30 @@ public abstract class MixinChunk implements IChunkTileEntityMapHolder {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "fillChunk", at = @At("RETURN"))
|
||||
private void angelica$onBiomesFilled(byte[] data, int primaryBitMask, int addBitMask, boolean groundUp, CallbackInfo ci) {
|
||||
if (!groundUp || !this.worldObj.isRemote) return;
|
||||
final long hash = angelica$hashBiomes();
|
||||
if (!this.angelica$biomeHashValid) {
|
||||
this.angelica$biomeHashValid = true;
|
||||
this.angelica$biomeHash = hash;
|
||||
return;
|
||||
}
|
||||
if (hash == this.angelica$biomeHash) return;
|
||||
this.angelica$biomeHash = hash;
|
||||
ChunkBiomeDataChangedEvent.post(this.xPosition, this.zPosition);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private long angelica$hashBiomes() {
|
||||
final WorldChunkManager wcm = this.worldObj.getWorldChunkManager();
|
||||
long hash = Fnv1a64.initialState();
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
hash = Fnv1a64.hashStep(hash, getBiomeGenForWorldCoords(x, z, wcm).biomeID);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -148,7 +148,11 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
|
||||
this.mc.entityRenderer.enableLightmap(partialTicks);
|
||||
|
||||
final double camX = lerp(entity.lastTickPosX, entity.posX, partialTicks);
|
||||
final double camY = lerp(entity.lastTickPosY, entity.posY, partialTicks);
|
||||
// Minecraft's setupCameraTransform bakes -eyeHeight into the modelview, which would normally
|
||||
// require feet here; CeleritasWorldRenderer.createChunkRenderMatrices compensates this by
|
||||
// post-multiplying the chunk-shader modelview with translate(0, +eyeHeight, 0).
|
||||
// Otherwise, we get issues with Iris shaders getting normals at a shifted y-position.
|
||||
final double camY = lerp(entity.lastTickPosY, entity.posY, partialTicks) + entity.getEyeHeight();
|
||||
final double camZ = lerp(entity.lastTickPosZ, entity.posZ, partialTicks);
|
||||
|
||||
try {
|
||||
|
||||
+2
@@ -51,6 +51,8 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe
|
||||
|
||||
pipeline.set(Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimensionName()));
|
||||
|
||||
GLStateManager.setShaderColor(1f, 1f, 1f, 1f);
|
||||
|
||||
pipeline.get().beginLevelRendering();
|
||||
}
|
||||
|
||||
|
||||
+73
-3
@@ -1,29 +1,45 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntFunction;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.shaderpack.materialmap.NamespacedId;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.renderer.entity.RenderDragon;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.boss.EntityDragon;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Mixin to set the entity ID to "end_crystal_beam" when rendering ender dragon healing beams.
|
||||
* This allows shaders to apply special effects to the healing beams separately from the dragon itself.
|
||||
* Mixin allows devs to target the ender crystal beams as a separate entity.
|
||||
* Also sets the special condition "lightning" on the dragon's death beams.
|
||||
*/
|
||||
@Mixin(RenderDragon.class)
|
||||
public class MixinRenderDragon {
|
||||
public abstract class MixinRenderDragon {
|
||||
@Unique
|
||||
private static final NamespacedId END_CRYSTAL_BEAM = new NamespacedId("minecraft", "end_crystal_beam");
|
||||
|
||||
@Unique
|
||||
private int angelica$previousEntityId = -1;
|
||||
|
||||
@Unique
|
||||
private boolean angelica$deathBeamsActive = false;
|
||||
|
||||
@Unique
|
||||
private int angelica$depthPassReplay = 0;
|
||||
|
||||
@Invoker("renderEquippedItems")
|
||||
protected abstract void angelica$invokeRenderEquippedItems(EntityDragon dragon, float partialTicks);
|
||||
|
||||
@Inject(
|
||||
method = "doRender(Lnet/minecraft/entity/boss/EntityDragon;DDDFF)V",
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glPushMatrix()V", ordinal = 0, shift = At.Shift.AFTER, remap = false)
|
||||
@@ -52,4 +68,58 @@ public class MixinRenderDragon {
|
||||
angelica$previousEntityId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We adapt the 2 pass structure that Modern Iris uses for the death beams.
|
||||
* Replay like this so mixins that target the vanilla code hopefully runs too.
|
||||
* <p>
|
||||
* Pass 1: Write the depth buffer.
|
||||
* Pass 2: Write color.
|
||||
*/
|
||||
@Inject(method = "renderEquippedItems(Lnet/minecraft/entity/boss/EntityDragon;F)V", at = @At("HEAD"))
|
||||
private void angelica$beginDeathBeamsLightningBuffer(EntityDragon dragon, float partialTicks, CallbackInfo ci) {
|
||||
if (angelica$depthPassReplay > 0) return;
|
||||
if (dragon.deathTicks > 0) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.LIGHTNING);
|
||||
angelica$deathBeamsActive = true;
|
||||
|
||||
angelica$depthPassReplay++;
|
||||
GLStateManager.glColorMask(false, false, false, false);
|
||||
angelica$invokeRenderEquippedItems(dragon, partialTicks);
|
||||
GLStateManager.glColorMask(true, true, true, true);
|
||||
angelica$depthPassReplay--;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't render items twice
|
||||
@WrapOperation(
|
||||
method = "renderEquippedItems(Lnet/minecraft/entity/boss/EntityDragon;F)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderLiving;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V")
|
||||
)
|
||||
private void angelica$skipSuperDuringReplay(RenderDragon self, EntityLivingBase entity, float partialTicks, Operation<Void> original) {
|
||||
if (angelica$depthPassReplay == 0) {
|
||||
original.call(self, entity, partialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
// No-op the depth buffer being set to false on first pass
|
||||
@WrapOperation(
|
||||
method = "renderEquippedItems(Lnet/minecraft/entity/boss/EntityDragon;F)V",
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthMask(Z)V", ordinal = 0, remap = false)
|
||||
)
|
||||
private void angelica$keepDepthMaskDuringReplay(boolean flag, Operation<Void> original) {
|
||||
if (angelica$depthPassReplay == 0) {
|
||||
original.call(flag);
|
||||
}
|
||||
}
|
||||
|
||||
// End replay
|
||||
@Inject(method = "renderEquippedItems(Lnet/minecraft/entity/boss/EntityDragon;F)V", at = @At("RETURN"))
|
||||
private void angelica$endDeathBeamsLighting(EntityDragon dragon, float partialTicks, CallbackInfo ci) {
|
||||
if (angelica$depthPassReplay > 0) return;
|
||||
if (angelica$deathBeamsActive) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
angelica$deathBeamsActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.EntityIdHelper;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
@@ -25,7 +27,14 @@ public class MixinRenderManager {
|
||||
private void iris$wrapDoRender(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
final boolean lightning = EntityIdHelper.isLightningBolt(entity);
|
||||
if (lightning) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.LIGHTNING);
|
||||
}
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
if (lightning) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
}
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
}
|
||||
}
|
||||
+9
@@ -2,6 +2,8 @@ package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.EntityIdHelper;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
@@ -23,7 +25,14 @@ public class MixinRenderManagerDAPI {
|
||||
private void iris$wrapDoRenderDragonAPI(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
final boolean lightning = EntityIdHelper.isLightningBolt(entity);
|
||||
if (lightning) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.LIGHTNING);
|
||||
}
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
if (lightning) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
}
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user