mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a66db1517a | ||
|
|
269b7245d3 | ||
|
|
67f2484976 | ||
|
|
1c8687e6fd | ||
|
|
e6bbd155da | ||
|
|
2f64fef6a6 | ||
|
|
b0fd1ea46e |
No files matched your search
@@ -307,6 +307,11 @@ public class DisplayListManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void recordSecondaryColor(float r, float g, float b) {
|
||||
drawBarrier();
|
||||
currentRecorder.writeSecondaryColor(r, g, b);
|
||||
}
|
||||
|
||||
public static void recordColorMask(boolean r, boolean g, boolean b, boolean a) {
|
||||
drawBarrier();
|
||||
currentRecorder.writeColorMask(r, g, b, a);
|
||||
|
||||
@@ -99,6 +99,7 @@ public class Feature {
|
||||
));
|
||||
attribToFeatures.put(GL11.GL_CURRENT_BIT, ImmutableSet.of(
|
||||
GLStateManager.getColor()
|
||||
, GLStateManager.getSecondaryColor() // Current secondary color
|
||||
, ShaderManager.getNormalStack() // Current normal vector
|
||||
, ShaderManager.getTexCoordStack() // Current texture coordinates
|
||||
// Current color index
|
||||
@@ -122,6 +123,7 @@ public class Feature {
|
||||
, GLStateManager.getBlendMode()
|
||||
, GLStateManager.getColorLogicOpState()
|
||||
, GLStateManager.getColorMaterial()
|
||||
, GLStateManager.getColorSumState()
|
||||
, GLStateManager.getCullState()
|
||||
, GLStateManager.getDepthTest()
|
||||
, GLStateManager.getDitherState()
|
||||
@@ -197,6 +199,7 @@ public class Feature {
|
||||
));
|
||||
attribToFeatures.put(GL11.GL_FOG_BIT, ImmutableSet.of(
|
||||
GLStateManager.getFogMode()
|
||||
, GLStateManager.getColorSumState()
|
||||
, GLStateManager.getFogState()
|
||||
// ^^ Fog density
|
||||
// ^^ Linear fog start
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
@@ -104,6 +105,9 @@ class GLContextState {
|
||||
public final FogStateStack fogState = new FogStateStack();
|
||||
public final BooleanStateStack fogMode = track(new BooleanStateStack(GL11.GL_FOG, false, true));
|
||||
public final Color4Stack color = new Color4Stack();
|
||||
// GL_CURRENT_SECONDARY_COLOR - alpha is always 1 and unused, the color sum only adds RGB
|
||||
public final Color4Stack secondaryColor = new Color4Stack(new Color4(0.0F, 0.0F, 0.0F, 1.0F));
|
||||
public final BooleanStateStack colorSumState = track(new BooleanStateStack(GL14.GL_COLOR_SUM, false, true));
|
||||
public final Color4Stack clearColor = new Color4Stack(new Color4(0.0F, 0.0F, 0.0F, 0.0F));
|
||||
public final ColorMaskStack colorMask = new ColorMaskStack();
|
||||
public final IntegerStateStack drawBuffer = new IntegerStateStack(GLStateManager.DEFAULT_DRAW_BUFFER);
|
||||
@@ -181,7 +185,7 @@ class GLContextState {
|
||||
public final int[] clientAttribSavedVertexFlags = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
|
||||
public int clientAttribStackPointer = 0;
|
||||
public final boolean[] restoreUnitChanged = new boolean[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
public boolean restoreDepthChanged, restoreBlendChanged, restoreColorMaskChanged, restoreClearColorChanged, restoreDrawBufferChanged, restoreLogicOpChanged, restoreStencilChanged, restoreViewportChanged, restoreLineChanged, restorePointChanged, restorePolygonChanged, restoreActiveUnitChanged;
|
||||
public boolean restoreDepthChanged, restoreBlendChanged, restoreColorMaskChanged, restoreClearColorChanged, restoreDrawBufferChanged, restoreLogicOpChanged, restoreStencilChanged, restoreViewportChanged, restoreLineChanged, restorePointChanged, restorePolygonChanged, restoreActiveUnitChanged, restoreSecondaryColorChanged;
|
||||
public final BlendState vanillaBlendBefore = new BlendState();
|
||||
public final BlendState vanillaBlendAfter = new BlendState();
|
||||
public boolean vanillaBlendEnabledBefore;
|
||||
|
||||
@@ -504,6 +504,7 @@ public class GLStateManager {
|
||||
.addFeature(GL11.GL_COLOR_WRITEMASK)
|
||||
.addFeature(GL11.GL_CURRENT_COLOR)
|
||||
.addFeature(GL11.GL_CURRENT_NORMAL)
|
||||
.addFeature(GL14.GL_CURRENT_SECONDARY_COLOR)
|
||||
.addFeature(GL11.GL_CURRENT_RASTER_COLOR)
|
||||
.addFeature(GL11.GL_CURRENT_RASTER_POSITION)
|
||||
.addFeature(GL11.GL_CURRENT_RASTER_TEXTURE_COORDS)
|
||||
@@ -659,6 +660,7 @@ public class GLStateManager {
|
||||
case GL11.GL_BLEND -> enableBlend();
|
||||
case GL11.GL_COLOR_MATERIAL -> enableColorMaterial();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> glCtx.colorLogicOpState.enable();
|
||||
case GL14.GL_COLOR_SUM -> glCtx.colorSumState.enable();
|
||||
case GL11.GL_CULL_FACE -> enableCull();
|
||||
case GL11.GL_DEPTH_TEST -> enableDepthTest();
|
||||
case GL11.GL_DITHER -> glCtx.ditherState.enable();
|
||||
@@ -740,6 +742,7 @@ public class GLStateManager {
|
||||
case GL11.GL_BLEND -> disableBlend();
|
||||
case GL11.GL_COLOR_MATERIAL -> disableColorMaterial();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> glCtx.colorLogicOpState.disable();
|
||||
case GL14.GL_COLOR_SUM -> glCtx.colorSumState.disable();
|
||||
case GL11.GL_CULL_FACE -> disableCull();
|
||||
case GL11.GL_DEPTH_TEST -> disableDepthTest();
|
||||
case GL11.GL_DITHER -> glCtx.ditherState.disable();
|
||||
@@ -815,6 +818,7 @@ public class GLStateManager {
|
||||
case GL11.GL_BLEND -> glCtx.blendMode.isEnabled();
|
||||
case GL11.GL_COLOR_MATERIAL -> glCtx.colorMaterial.isEnabled();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> glCtx.colorLogicOpState.isEnabled();
|
||||
case GL14.GL_COLOR_SUM -> glCtx.colorSumState.isEnabled();
|
||||
case GL11.GL_CULL_FACE -> glCtx.cullState.isEnabled();
|
||||
case GL11.GL_DEPTH_TEST -> glCtx.depthTest.isEnabled();
|
||||
case GL11.GL_DITHER -> glCtx.ditherState.isEnabled();
|
||||
@@ -890,6 +894,7 @@ public class GLStateManager {
|
||||
case GL11.GL_BLEND -> glCtx.blendMode.isEnabled();
|
||||
case GL11.GL_COLOR_MATERIAL -> glCtx.colorMaterial.isEnabled();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> glCtx.colorLogicOpState.isEnabled();
|
||||
case GL14.GL_COLOR_SUM -> glCtx.colorSumState.isEnabled();
|
||||
case GL11.GL_CULL_FACE -> glCtx.cullState.isEnabled();
|
||||
case GL11.GL_DEPTH_TEST -> glCtx.depthTest.isEnabled();
|
||||
case GL11.GL_DEPTH_WRITEMASK -> glCtx.depthState.isEnabled();
|
||||
@@ -1133,6 +1138,7 @@ public class GLStateManager {
|
||||
case GL11.GL_TEXTURE_MATRIX -> glCtx.textures.getTextureUnitMatrix(getActiveTextureUnit()).get(0, params);
|
||||
case GL11.GL_COLOR_CLEAR_VALUE -> glCtx.clearColor.get(params);
|
||||
case GL11.GL_CURRENT_COLOR -> glCtx.color.get(params);
|
||||
case GL14.GL_CURRENT_SECONDARY_COLOR -> glCtx.secondaryColor.get(params);
|
||||
case GL11.GL_DEPTH_RANGE -> {
|
||||
final int pos = params.position();
|
||||
params.put(pos, (float) glCtx.viewportState.depthRangeNear);
|
||||
@@ -1231,7 +1237,7 @@ public class GLStateManager {
|
||||
}
|
||||
case GL11.GL_MODELVIEW_MATRIX, GL11.GL_PROJECTION_MATRIX, GL11.GL_TEXTURE_MATRIX -> widenFromFloat(pname, params, 16);
|
||||
case GL11.GL_COLOR_CLEAR_VALUE, GL11.GL_CURRENT_COLOR, GL11.GL_CURRENT_TEXTURE_COORDS, GL11.GL_FOG_COLOR,
|
||||
GL11.GL_LIGHT_MODEL_AMBIENT, GL14.GL_BLEND_COLOR -> widenFromFloat(pname, params, 4);
|
||||
GL11.GL_LIGHT_MODEL_AMBIENT, GL14.GL_BLEND_COLOR, GL14.GL_CURRENT_SECONDARY_COLOR -> widenFromFloat(pname, params, 4);
|
||||
case GL11.GL_CURRENT_NORMAL -> widenFromFloat(pname, params, 3);
|
||||
default -> {
|
||||
if (!HAS_MULTIPLE_SET.contains(pname)) {
|
||||
@@ -1754,6 +1760,40 @@ public class GLStateManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void glSecondaryColor3f(float red, float green, float blue) {
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordSecondaryColor(red, green, blue);
|
||||
if (mode == RecordMode.COMPILE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
changeSecondaryColor(red, green, blue);
|
||||
}
|
||||
|
||||
public static void glSecondaryColor3d(double red, double green, double blue) {
|
||||
glSecondaryColor3f((float) red, (float) green, (float) blue);
|
||||
}
|
||||
|
||||
public static void glSecondaryColor3b(byte red, byte green, byte blue) {
|
||||
glSecondaryColor3f(b2f(red), b2f(green), b2f(blue));
|
||||
}
|
||||
|
||||
public static void glSecondaryColor3ub(byte red, byte green, byte blue) {
|
||||
glSecondaryColor3f(ub2f(red), ub2f(green), ub2f(blue));
|
||||
}
|
||||
|
||||
/** Helper for glSecondaryColor* - the color sum is emulated by the FFP shaders, nothing is sent to the driver. */
|
||||
private static void changeSecondaryColor(float red, float green, float blue) {
|
||||
final GLContextState glCtx = ctx();
|
||||
if (!isCachingEnabled() || red != glCtx.secondaryColor.getRed() || green != glCtx.secondaryColor.getGreen() || blue != glCtx.secondaryColor.getBlue()) {
|
||||
glCtx.secondaryColor.setRed(red);
|
||||
glCtx.secondaryColor.setGreen(green);
|
||||
glCtx.secondaryColor.setBlue(blue);
|
||||
glCtx.fragmentGeneration++;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Color4 DirtyColor = new Color4(-1.0F, -1.0F, -1.0F, -1.0F);
|
||||
|
||||
public static void clearCurrentColor() {
|
||||
@@ -3656,6 +3696,9 @@ public class GLStateManager {
|
||||
glCtx.restoreDrawBufferChanged = glCtx.drawBuffer.topChanged();
|
||||
glCtx.restoreLogicOpChanged = glCtx.logicOpMode.topChanged();
|
||||
}
|
||||
if ((mask & GL11.GL_CURRENT_BIT) != 0) {
|
||||
glCtx.restoreSecondaryColorChanged = glCtx.secondaryColor.topChanged();
|
||||
}
|
||||
if ((mask & GL11.GL_STENCIL_BUFFER_BIT) != 0) {
|
||||
glCtx.restoreStencilChanged = glCtx.stencilState.topChanged();
|
||||
}
|
||||
@@ -3832,6 +3875,8 @@ public class GLStateManager {
|
||||
ShaderManager.bumpTexCoordGeneration();
|
||||
glCtx.dirtyTexCoordAttrib = true;
|
||||
}
|
||||
// The secondary color is a fragment stage uniform, not a vertex attribute
|
||||
if (glCtx.restoreSecondaryColorChanged) glCtx.fragmentGeneration++;
|
||||
}
|
||||
|
||||
postVanillaBlendChangeIfMoved(blendSnapshotted);
|
||||
@@ -7411,6 +7456,14 @@ public class GLStateManager {
|
||||
return ctx().color;
|
||||
}
|
||||
|
||||
public static Color4Stack getSecondaryColor() {
|
||||
return ctx().secondaryColor;
|
||||
}
|
||||
|
||||
public static BooleanStateStack getColorSumState() {
|
||||
return ctx().colorSumState;
|
||||
}
|
||||
|
||||
public static Color4Stack getClearColor() {
|
||||
return ctx().clearColor;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ public final class FFPUniformBlock {
|
||||
public static final int TEX_ENV_COLOR_2 = vec4("u_TexEnvColor2");
|
||||
public static final int TEX_ENV_COLOR_3 = vec4("u_TexEnvColor3");
|
||||
public static final int OVERLAY_COLOR = vec4("u_OverlayColor");
|
||||
public static final int SECONDARY_COLOR = vec3("u_SecondaryColor");
|
||||
public static final int FOG_PARAMS = vec4("u_FogParams");
|
||||
public static final int FOG_COLOR = vec4("u_FogColor");
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.lwjgl.opengl.GL13;
|
||||
* Packed-long fragment shader permutation key for FFP emulation.
|
||||
*
|
||||
* Layout:
|
||||
* long[0]: global bits (12) + unit 0 (47 bits at offset 12)
|
||||
* long[0]: global bits (13) + unit 0 (47 bits at offset 13)
|
||||
* long[1..3]: unit 1..3 (47 bits each, low-aligned)
|
||||
* Only max(1, nrEnabledUnits) longs are significant.
|
||||
*
|
||||
@@ -63,7 +63,7 @@ public final class FragmentKey {
|
||||
public static final int FOG_EXP = 2;
|
||||
public static final int FOG_EXP2 = 3;
|
||||
|
||||
private static final int GLOBAL_BITS = 12;
|
||||
private static final int GLOBAL_BITS = 13;
|
||||
private static final int BIT_FOG_MODE = 0; // 2 bits
|
||||
private static final int BIT_ALPHA_TEST = 2; // 1 bit
|
||||
private static final int BIT_ALPHA_FUNC = 3; // 3 bits
|
||||
@@ -71,6 +71,7 @@ public final class FragmentKey {
|
||||
private static final int BIT_NR_ENABLED_UNITS = 7; // 3 bits
|
||||
private static final int BIT_OVERLAY_ENABLED = 10; // 1 bit
|
||||
private static final int BIT_LINE_STIPPLE = 11; // 1 bit
|
||||
private static final int BIT_COLOR_SUM = 12; // 1 bit
|
||||
|
||||
private static final int U_ENABLED = 0;
|
||||
private static final int U_MODE = 1; // 3 bits
|
||||
@@ -130,10 +131,12 @@ public final class FragmentKey {
|
||||
global |= (1L << BIT_LINE_STIPPLE);
|
||||
}
|
||||
|
||||
// Separate specular
|
||||
// Separate specular / color sum
|
||||
if (GLStateManager.getLightingState().isEnabled()
|
||||
&& GLStateManager.getLightModel().colorControl == GL12.GL_SEPARATE_SPECULAR_COLOR) {
|
||||
global |= (1L << BIT_SEPARATE_SPECULAR);
|
||||
} else if (GLStateManager.getColorSumState().isEnabled()) {
|
||||
global |= (1L << BIT_COLOR_SUM);
|
||||
}
|
||||
|
||||
// Per-unit state
|
||||
@@ -238,6 +241,7 @@ public final class FragmentKey {
|
||||
public boolean alphaTestEnabled() { return ((packed[0] >> BIT_ALPHA_TEST) & 1) != 0; }
|
||||
public int alphaTestFunc() { return (int) ((packed[0] >> BIT_ALPHA_FUNC) & 0x7); }
|
||||
public boolean separateSpecular() { return ((packed[0] >> BIT_SEPARATE_SPECULAR) & 1) != 0; }
|
||||
public boolean colorSum() { return ((packed[0] >> BIT_COLOR_SUM) & 1) != 0; }
|
||||
public boolean lineStipple() { return ((packed[0] >> BIT_LINE_STIPPLE) & 1) != 0; }
|
||||
public int nrEnabledUnits() { return (int) ((packed[0] >> BIT_NR_ENABLED_UNITS) & 0x7); }
|
||||
public boolean overlayEnabled() { return ((packed[0] >> BIT_OVERLAY_ENABLED) & 1) != 0; }
|
||||
@@ -374,10 +378,10 @@ public final class FragmentKey {
|
||||
default -> "?";
|
||||
};
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("FFPFragmentKey[fog=%s alpha=%b(%s) specSep=%b overlay=%b units=%d",
|
||||
sb.append(String.format("FFPFragmentKey[fog=%s alpha=%b(%s) specSep=%b colorSum=%b overlay=%b units=%d",
|
||||
fogName, alphaTestEnabled(),
|
||||
alphaTestEnabled() ? String.format("0x%04X", decodeAlphaFunc(alphaTestFunc())) : "-",
|
||||
separateSpecular(), overlayEnabled(), nrEnabledUnits()));
|
||||
separateSpecular(), colorSum(), overlayEnabled(), nrEnabledUnits()));
|
||||
for (int i = 0; i < nrEnabledUnits(); i++) {
|
||||
if (!unitEnabled(i)) {
|
||||
sb.append(String.format(" u%d=OFF", i));
|
||||
|
||||
@@ -276,6 +276,10 @@ public final class FragmentShaderGenerator {
|
||||
sb.append(" // Add separate specular\n");
|
||||
sb.append(" color.rgb += v_SpecularColor;\n");
|
||||
}
|
||||
if (key.colorSum()) {
|
||||
sb.append(" // Color sum - GL_COLOR_SUM with the current secondary color\n");
|
||||
sb.append(" color.rgb += u_SecondaryColor;\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitAlphaTest(StringBuilder sb, FragmentKey key) {
|
||||
|
||||
@@ -331,6 +331,9 @@ public class Uniforms {
|
||||
GLStateManager.getOverlayR(), GLStateManager.getOverlayG(),
|
||||
GLStateManager.getOverlayB(), GLStateManager.getOverlayA());
|
||||
|
||||
final var secondary = GLStateManager.getSecondaryColor();
|
||||
putVec3(FFPUniformBlock.SECONDARY_COLOR, secondary.getRed(), secondary.getGreen(), secondary.getBlue());
|
||||
|
||||
// Mesa STATE_FOG_PARAMS_OPTIMIZED
|
||||
final FogState fog = GLStateManager.getFogState();
|
||||
final float start = fog.getStart();
|
||||
|
||||
+7
@@ -274,6 +274,13 @@ public final class CommandBufferExecutor {
|
||||
ptr += 16;
|
||||
GLStateManager.glColor4f(r, g, b, a);
|
||||
}
|
||||
case GLCommand.SECONDARY_COLOR -> {
|
||||
final float r = memGetFloat(ptr);
|
||||
final float g = memGetFloat(ptr + 4);
|
||||
final float b = memGetFloat(ptr + 8);
|
||||
ptr += 12;
|
||||
GLStateManager.glSecondaryColor3f(r, g, b);
|
||||
}
|
||||
case GLCommand.CLEAR_COLOR -> {
|
||||
final float r = memGetFloat(ptr);
|
||||
final float g = memGetFloat(ptr + 4);
|
||||
|
||||
@@ -356,6 +356,14 @@ public final class CommandRecorder {
|
||||
writeFloat(a);
|
||||
}
|
||||
|
||||
public void writeSecondaryColor(float r, float g, float b) {
|
||||
ensureCapacity(16);
|
||||
writeInt(GLCommand.SECONDARY_COLOR);
|
||||
writeFloat(r);
|
||||
writeFloat(g);
|
||||
writeFloat(b);
|
||||
}
|
||||
|
||||
public void writeClearColor(float r, float g, float b, float a) {
|
||||
ensureCapacity(20);
|
||||
writeInt(GLCommand.CLEAR_COLOR);
|
||||
|
||||
@@ -61,6 +61,7 @@ public final class GLCommand {
|
||||
public static final int COLOR = 54; // [cmd:4][r:4f][g:4f][b:4f][a:4f]
|
||||
public static final int CLEAR_COLOR = 55; // [cmd:4][r:4f][g:4f][b:4f][a:4f]
|
||||
public static final int BLEND_COLOR = 56; // [cmd:4][r:4f][g:4f][b:4f][a:4f]
|
||||
public static final int SECONDARY_COLOR = 57; // [cmd:4][r:4f][g:4f][b:4f]
|
||||
|
||||
// === Mixed int+float commands ===
|
||||
public static final int ALPHA_FUNC = 60; // [cmd:4][func:4][ref:4f]
|
||||
@@ -155,6 +156,7 @@ public final class GLCommand {
|
||||
case COLOR -> "COLOR";
|
||||
case CLEAR_COLOR -> "CLEAR_COLOR";
|
||||
case BLEND_COLOR -> "BLEND_COLOR";
|
||||
case SECONDARY_COLOR -> "SECONDARY_COLOR";
|
||||
case ALPHA_FUNC -> "ALPHA_FUNC";
|
||||
case FOGF -> "FOGF";
|
||||
case LIGHTF -> "LIGHTF";
|
||||
@@ -211,7 +213,7 @@ public final class GLCommand {
|
||||
// Three int commands (16 bytes)
|
||||
case GLCommand.STENCIL_FUNC, GLCommand.STENCIL_OP, GLCommand.TEX_PARAMETERI,
|
||||
GLCommand.LIGHTF, GLCommand.LIGHTI,
|
||||
GLCommand.MATERIALF, GLCommand.TEX_PARAMETERF -> 16;
|
||||
GLCommand.MATERIALF, GLCommand.TEX_PARAMETERF, GLCommand.SECONDARY_COLOR -> 16;
|
||||
|
||||
// Four int commands (20 bytes)
|
||||
case GLCommand.VIEWPORT, GLCommand.BLEND_FUNC, GLCommand.COLOR_MASK,
|
||||
|
||||
@@ -142,6 +142,7 @@ public class GLSMRedirector {
|
||||
private static final String GLU = "org/lwjgl/util/glu/GLU";
|
||||
private static final String OpenGlHelper = "net/minecraft/client/renderer/OpenGlHelper";
|
||||
private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate";
|
||||
private static final String EXTSecondaryColor = "org/lwjgl/opengl/EXTSecondaryColor";
|
||||
private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture";
|
||||
private static final String ARBShaderObjects = "org/lwjgl/opengl/ARBShaderObjects";
|
||||
private static final String ARBInstancedArrays = "org/lwjgl/opengl/ARBInstancedArrays";
|
||||
@@ -403,7 +404,12 @@ public class GLSMRedirector {
|
||||
.add("glBlendEquation")
|
||||
.add("glMultiDrawArrays")
|
||||
.add("glPointParameterf")
|
||||
.add("glPointParameteri");
|
||||
.add("glPointParameteri")
|
||||
// Removed in core profile - emulated by the FFP shaders, calling through would abort the JVM
|
||||
.add("glSecondaryColor3f")
|
||||
.add("glSecondaryColor3d")
|
||||
.add("glSecondaryColor3b")
|
||||
.add("glSecondaryColor3ub");
|
||||
final var gl15 = RedirectMap.newMap()
|
||||
.add("glGenBuffers")
|
||||
.add("glBindBuffer")
|
||||
@@ -589,6 +595,11 @@ public class GLSMRedirector {
|
||||
.add("isFramebufferEnabled")
|
||||
);
|
||||
methodRedirects.put(EXTBlendFunc, RedirectMap.newMap().add("glBlendFuncSeparateEXT", "tryBlendFuncSeparate"));
|
||||
methodRedirects.put(EXTSecondaryColor, RedirectMap.newMap()
|
||||
.add("glSecondaryColor3bEXT", "glSecondaryColor3b")
|
||||
.add("glSecondaryColor3fEXT", "glSecondaryColor3f")
|
||||
.add("glSecondaryColor3dEXT", "glSecondaryColor3d")
|
||||
.add("glSecondaryColor3ubEXT", "glSecondaryColor3ub"));
|
||||
|
||||
// ARB
|
||||
methodRedirects.put(ARBMultiTexture, RedirectMap.newMap()
|
||||
|
||||
@@ -4,8 +4,11 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -22,6 +25,7 @@ public class GLSM_CoreRemovedCaps_GLTest {
|
||||
cap("GL_POLYGON_STIPPLE", GL11.GL_POLYGON_STIPPLE),
|
||||
cap("GL_INDEX_LOGIC_OP", GL11.GL_INDEX_LOGIC_OP),
|
||||
cap("GL_AUTO_NORMAL", GL11.GL_AUTO_NORMAL),
|
||||
cap("GL_COLOR_SUM", GL14.GL_COLOR_SUM),
|
||||
cap("GL_MAP1_COLOR_4", GL11.GL_MAP1_COLOR_4),
|
||||
cap("GL_MAP1_INDEX", GL11.GL_MAP1_INDEX),
|
||||
cap("GL_MAP1_NORMAL", GL11.GL_MAP1_NORMAL),
|
||||
@@ -46,6 +50,14 @@ public class GLSM_CoreRemovedCaps_GLTest {
|
||||
return Arguments.of(name, value);
|
||||
}
|
||||
|
||||
private static void assertSecondaryColor(float red, float green, float blue) {
|
||||
final FloatBuffer params = BufferUtils.createFloatBuffer(4);
|
||||
GLStateManager.glGetFloat(GL14.GL_CURRENT_SECONDARY_COLOR, params);
|
||||
assertEquals(red, params.get(0), "red must round-trip through the cache");
|
||||
assertEquals(green, params.get(1), "green must round-trip through the cache");
|
||||
assertEquals(blue, params.get(2), "blue must round-trip through the cache");
|
||||
}
|
||||
|
||||
private static void assertNoGlError(String what) {
|
||||
final int error = GL11.glGetError();
|
||||
assertEquals(GL11.GL_NO_ERROR, error, () -> what + " raised 0x" + Integer.toHexString(error));
|
||||
@@ -83,6 +95,71 @@ public class GLSM_CoreRemovedCaps_GLTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void secondaryColorIsCacheOnly() {
|
||||
try {
|
||||
// Calling through to the driver here aborts the JVM in a core profile - the color sum is emulated by the FFP shaders
|
||||
GLStateManager.glSecondaryColor3f(0.25F, 0.5F, 0.75F);
|
||||
assertNoGlError("glSecondaryColor3f");
|
||||
|
||||
assertSecondaryColor(0.25F, 0.5F, 0.75F);
|
||||
} finally {
|
||||
GLStateManager.glSecondaryColor3f(0.0F, 0.0F, 0.0F);
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void secondaryColorIsRestoredByPopAttrib() {
|
||||
try {
|
||||
GLStateManager.glSecondaryColor3f(0.125F, 0.25F, 0.375F);
|
||||
GLStateManager.glPushAttrib(GL11.GL_CURRENT_BIT);
|
||||
GLStateManager.glSecondaryColor3f(1.0F, 1.0F, 1.0F);
|
||||
GLStateManager.glPopAttrib();
|
||||
assertNoGlError("glPushAttrib/glSecondaryColor3f/glPopAttrib");
|
||||
|
||||
assertSecondaryColor(0.125F, 0.25F, 0.375F);
|
||||
} finally {
|
||||
GLStateManager.glSecondaryColor3f(0.0F, 0.0F, 0.0F);
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void colorSumIsRestoredByFogBitPopAttrib() {
|
||||
try {
|
||||
GLStateManager.glPushAttrib(GL11.GL_FOG_BIT);
|
||||
GLStateManager.glEnable(GL14.GL_COLOR_SUM);
|
||||
GLStateManager.glPopAttrib();
|
||||
assertNoGlError("glPushAttrib(GL_FOG_BIT)/glEnable(GL_COLOR_SUM)/glPopAttrib");
|
||||
assertFalse(GLStateManager.glIsEnabled(GL14.GL_COLOR_SUM));
|
||||
} finally {
|
||||
GLStateManager.glDisable(GL14.GL_COLOR_SUM);
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void secondaryColorReplaysFromDisplayList() {
|
||||
final int list = GLStateManager.glGenLists(1);
|
||||
try {
|
||||
GLStateManager.glNewList(list, GL11.GL_COMPILE);
|
||||
GLStateManager.glSecondaryColor3f(0.5F, 0.625F, 0.75F);
|
||||
GLStateManager.glEndList();
|
||||
assertNoGlError("glSecondaryColor3f display list compile");
|
||||
|
||||
GLStateManager.glSecondaryColor3f(0.0F, 0.0F, 0.0F);
|
||||
GLStateManager.glCallList(list);
|
||||
assertNoGlError("glSecondaryColor3f display list replay");
|
||||
|
||||
assertSecondaryColor(0.5F, 0.625F, 0.75F);
|
||||
} finally {
|
||||
GLStateManager.glDeleteLists(list, 1);
|
||||
GLStateManager.glSecondaryColor3f(0.0F, 0.0F, 0.0F);
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void displayListReplayIsCacheOnly() {
|
||||
final int list = GLStateManager.glGenLists(1);
|
||||
|
||||
@@ -204,10 +204,19 @@ public class BatchingFontRenderer {
|
||||
return (argb & 0xFF000000) | (red << 16) | (green << 8) | blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* True only for a perspective projection (world-space text: signs, nameplates, etc).
|
||||
* GUI/HUD text uses an orthographic projection and must never be shaded by world lighting -
|
||||
* mods rely on getting back the exact color they requested (e.g. GTNHLib's ColorResource).
|
||||
*/
|
||||
private static boolean isWorldSpaceText() {
|
||||
return GLStateManager.getProjectionMatrix().m33() == 0.0f;
|
||||
}
|
||||
|
||||
private void captureLightmapState() {
|
||||
final int unitBinding = GLStateManager.getTextures().getTextureUnitBindings(LIGHTMAP_TEX_UNIT).getBinding();
|
||||
|
||||
final boolean active = GLStateManager.getProjectionMatrix().m33() == 0.0f && unitBinding != 0;
|
||||
final boolean active = isWorldSpaceText() && unitBinding != 0;
|
||||
|
||||
float u = 0.0f;
|
||||
float v = 0.0f;
|
||||
@@ -1236,7 +1245,7 @@ public class BatchingFontRenderer {
|
||||
|
||||
this.beginBatch();
|
||||
this.captureLightmapState();
|
||||
this.lightingFactorActive = FFPVertexLighting.modulatesVertexColor(this.lightingFactor);
|
||||
this.lightingFactorActive = isWorldSpaceText() && FFPVertexLighting.modulatesVertexColor(this.lightingFactor);
|
||||
float curX = anchorX;
|
||||
try {
|
||||
final int totalStringLength = string.length();
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public record DynamicLightsEntityFilter(List<String> modPrefixes, List<String> nameTerms, DynamicLightsEntityFilter.State state) {
|
||||
|
||||
public enum State {
|
||||
ANY,
|
||||
ENABLED,
|
||||
DISABLED
|
||||
}
|
||||
|
||||
private static final Pattern WHITESPACE = Pattern.compile("\\s+");
|
||||
private static final DynamicLightsEntityFilter MATCH_ALL = new DynamicLightsEntityFilter(List.of(), List.of(), State.ANY);
|
||||
|
||||
public DynamicLightsEntityFilter {
|
||||
modPrefixes = List.copyOf(modPrefixes);
|
||||
nameTerms = List.copyOf(nameTerms);
|
||||
}
|
||||
|
||||
public static DynamicLightsEntityFilter parse(String query) {
|
||||
if (query == null) {
|
||||
return MATCH_ALL;
|
||||
}
|
||||
|
||||
final var normalized = query.strip().toLowerCase(Locale.ROOT);
|
||||
if (normalized.isEmpty()) {
|
||||
return MATCH_ALL;
|
||||
}
|
||||
|
||||
final var modPrefixes = new ArrayList<String>();
|
||||
final var nameTerms = new ArrayList<String>();
|
||||
var wantEnabled = false;
|
||||
var wantDisabled = false;
|
||||
|
||||
for (final var token : WHITESPACE.split(normalized)) {
|
||||
switch (token) {
|
||||
case "$on" -> wantEnabled = true;
|
||||
case "$off" -> wantDisabled = true;
|
||||
default -> {
|
||||
if (token.length() > 1 && token.charAt(0) == '@') {
|
||||
modPrefixes.add(token.substring(1));
|
||||
} else {
|
||||
nameTerms.add(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final var state = wantEnabled == wantDisabled ? State.ANY : wantEnabled ? State.ENABLED : State.DISABLED;
|
||||
if (modPrefixes.isEmpty() && nameTerms.isEmpty() && state == State.ANY) {
|
||||
return MATCH_ALL;
|
||||
}
|
||||
return new DynamicLightsEntityFilter(modPrefixes, nameTerms, state);
|
||||
}
|
||||
|
||||
public boolean isMatchAll() {
|
||||
return modPrefixes.isEmpty() && nameTerms.isEmpty() && state == State.ANY;
|
||||
}
|
||||
|
||||
public boolean matches(String lowerName, String lowerModId, boolean enabled) {
|
||||
return matchesState(enabled) && matchesAnyMod(lowerModId) && containsAllTerms(lowerName);
|
||||
}
|
||||
|
||||
private boolean matchesState(boolean enabled) {
|
||||
return switch (state) {
|
||||
case ANY -> true;
|
||||
case ENABLED -> enabled;
|
||||
case DISABLED -> !enabled;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean matchesAnyMod(String lowerModId) {
|
||||
if (modPrefixes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (final var prefix : modPrefixes) {
|
||||
if (lowerModId.startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean containsAllTerms(String lowerName) {
|
||||
for (final var term : nameTerms) {
|
||||
if (!lowerName.contains(term)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityTypeEntry;
|
||||
|
||||
import net.coderbot.iris.gui.element.IrisGuiSlot;
|
||||
import net.coderbot.iris.gui.element.widget.IrisButton;
|
||||
|
||||
public class DynamicLightsEntityScreen extends GuiScreen {
|
||||
|
||||
private static final String ENABLED_PREFIX = EnumChatFormatting.GREEN + "[x] " + EnumChatFormatting.WHITE;
|
||||
private static final String DISABLED_PREFIX = EnumChatFormatting.DARK_GRAY + "[ ] " + EnumChatFormatting.GRAY;
|
||||
|
||||
private static List<EntityTypeEntry> entityTypes;
|
||||
|
||||
private final GuiScreen parent;
|
||||
private final String title = I18n.format("options.dynamiclights.entities.title");
|
||||
private final String info = I18n.format("options.dynamiclights.entities.info");
|
||||
|
||||
private List<EntityTypeEntry> displayed;
|
||||
private String countLabel;
|
||||
private String search = "";
|
||||
private boolean dirty;
|
||||
|
||||
private GuiTextField searchBox;
|
||||
private EntityRowList rowList;
|
||||
private IrisButton toggleButton;
|
||||
|
||||
public DynamicLightsEntityScreen(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
this.refilter();
|
||||
}
|
||||
|
||||
private static List<EntityTypeEntry> entityTypes() {
|
||||
if (entityTypes == null) {
|
||||
entityTypes = EntityLightConfig.getAllEntityTypes();
|
||||
}
|
||||
return entityTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
|
||||
this.searchBox = new GuiTextField(this.fontRendererObj, this.width / 2 - 150, 30, 300, 20);
|
||||
this.searchBox.setMaxStringLength(64);
|
||||
this.searchBox.setText(this.search);
|
||||
this.rowList = new EntityRowList();
|
||||
|
||||
this.toggleButton = new IrisButton(this.width / 2 - 154, this.height - 27, 150, 20, "", button -> this.toggleVisible());
|
||||
this.updateToggleButton();
|
||||
|
||||
this.buttonList.add(this.toggleButton);
|
||||
this.buttonList.add(new IrisButton(this.width / 2 + 4, this.height - 27, 150, 20, I18n.format("gui.done"), button -> this.onClose()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
private void onClose() {
|
||||
if (this.dirty) {
|
||||
EntityLightConfig.save();
|
||||
this.dirty = false;
|
||||
}
|
||||
this.mc.displayGuiScreen(this.parent);
|
||||
}
|
||||
|
||||
private void refilter() {
|
||||
final var filter = DynamicLightsEntityFilter.parse(this.search);
|
||||
if (filter.isMatchAll()) {
|
||||
this.displayed = entityTypes();
|
||||
} else {
|
||||
final var matches = new ArrayList<EntityTypeEntry>();
|
||||
for (final var entry : entityTypes()) {
|
||||
if (filter.matches(entry.getSearchName(), entry.getSearchModId(), EntityLightConfig.isEntityTypeEnabled(entry.getEntityClass()))) {
|
||||
matches.add(entry);
|
||||
}
|
||||
}
|
||||
this.displayed = matches;
|
||||
}
|
||||
this.countLabel = this.displayed.size() + " / " + entityTypes().size();
|
||||
this.updateToggleButton();
|
||||
}
|
||||
|
||||
private boolean anyDisplayedEnabled() {
|
||||
for (final var entry : this.displayed) {
|
||||
if (EntityLightConfig.isEntityTypeEnabled(entry.getEntityClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateToggleButton() {
|
||||
if (this.toggleButton == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var subset = this.displayed.size() != entityTypes().size();
|
||||
final var key = this.anyDisplayedEnabled()
|
||||
? (subset ? "options.dynamiclights.entities.disableshown" : "options.dynamiclights.entities.disableall")
|
||||
: (subset ? "options.dynamiclights.entities.enableshown" : "options.dynamiclights.entities.enableall");
|
||||
|
||||
this.toggleButton.displayString = I18n.format(key);
|
||||
this.toggleButton.enabled = !this.displayed.isEmpty();
|
||||
}
|
||||
|
||||
private void toggleVisible() {
|
||||
final var enable = !this.anyDisplayedEnabled();
|
||||
for (final var entry : this.displayed) {
|
||||
EntityLightConfig.setEntityTypeEnabled(entry.getEntityClass(), enable);
|
||||
}
|
||||
this.dirty = true;
|
||||
this.refilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
this.drawDefaultBackground();
|
||||
this.rowList.drawScreen(mouseX, mouseY, partialTicks);
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
|
||||
drawCenteredString(this.fontRendererObj, this.title, this.width / 2, 8, 0xFFFFFF);
|
||||
drawCenteredString(this.fontRendererObj, this.info, this.width / 2, 20, 0xA0A0A0);
|
||||
this.searchBox.drawTextBox();
|
||||
if (!this.searchBox.isFocused() && this.search.isEmpty()) {
|
||||
this.drawString(this.fontRendererObj, I18n.format("options.dynamiclights.entities.search"), this.width / 2 - 144, 36, 0x808080);
|
||||
}
|
||||
drawCenteredString(this.fontRendererObj, this.countLabel, this.width / 2, this.height - 39, 0x808080);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
this.searchBox.updateCursorCounter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if (!this.rowList.mouseClicked(mouseX, mouseY, mouseButton)) {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
this.searchBox.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseMovedOrUp(int mouseX, int mouseY, int state) {
|
||||
if (state == -1 || !this.rowList.mouseReleased(mouseX, mouseY, Mouse.getEventButton())) {
|
||||
super.mouseMovedOrUp(mouseX, mouseY, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton button) {
|
||||
if (button.enabled && button instanceof IrisButton irisButton) {
|
||||
irisButton.onPress();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) {
|
||||
if (this.searchBox.isFocused()) {
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.searchBox.setFocused(false);
|
||||
return;
|
||||
}
|
||||
this.searchBox.textboxKeyTyped(typedChar, keyCode);
|
||||
if (!this.searchBox.getText().equals(this.search)) {
|
||||
this.search = this.searchBox.getText();
|
||||
this.refilter();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.onClose();
|
||||
return;
|
||||
}
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
private class EntityRowList extends IrisGuiSlot {
|
||||
|
||||
EntityRowList() {
|
||||
super(DynamicLightsEntityScreen.this.mc, DynamicLightsEntityScreen.this.width, DynamicLightsEntityScreen.this.height, 56, DynamicLightsEntityScreen.this.height - 44, 18);
|
||||
this.setRenderBackground(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSize() {
|
||||
return displayed.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSelected(int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground() {}
|
||||
|
||||
@Override
|
||||
public int getListWidth() {
|
||||
return Math.min(400, DynamicLightsEntityScreen.this.width - 40);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean elementClicked(int index, boolean doubleClick, int mouseX, int mouseY, int button) {
|
||||
if (button != 0 || index >= displayed.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final var entry = displayed.get(index);
|
||||
EntityLightConfig.setEntityTypeEnabled(entry.getEntityClass(), !EntityLightConfig.isEntityTypeEnabled(entry.getEntityClass()));
|
||||
dirty = true;
|
||||
updateToggleButton();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawSlot(int index, int x, int y, int slotHeight, Tessellator tessellator, int mouseX, int mouseY) {
|
||||
final var entry = displayed.get(index);
|
||||
final var enabled = EntityLightConfig.isEntityTypeEnabled(entry.getEntityClass());
|
||||
final var label = (enabled ? ENABLED_PREFIX : DISABLED_PREFIX) + entry.getDisplayName() + EnumChatFormatting.DARK_GRAY + " (" + entry.getModId() + ")";
|
||||
|
||||
drawString(fontRendererObj, fontRendererObj.trimStringToWidth(label, this.getListWidth() - 8), x, y + 5, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +1,32 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfigStorage;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityTypeEntry;
|
||||
import jss.notfine.core.Settings;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpact;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.SubScreenOption;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DynamicLightsOptionPages {
|
||||
|
||||
public static OptionPage dynamicLights() {
|
||||
if (!DynamicLights.configEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_SHADER_FORCE.option)
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS_FRUSTUM_CULLING.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_ADAPTIVE_TICKING.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_CULL_TIMEOUT.option)
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS_SLOW_DIST.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_SLOWER_DIST.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_BACKGROUND_DIST.option)
|
||||
.build());
|
||||
|
||||
// Entity type toggles - grouped by mod ID
|
||||
List<EntityTypeEntry> allEntities = EntityLightConfig.getAllEntityTypes();
|
||||
Map<String, List<EntityTypeEntry>> byMod = new LinkedHashMap<>();
|
||||
|
||||
for (EntityTypeEntry entry : allEntities) {
|
||||
byMod.computeIfAbsent(entry.getModId(), _ -> new ArrayList<>()).add(entry);
|
||||
}
|
||||
|
||||
// Create a group for each mod's entities
|
||||
for (Map.Entry<String, List<EntityTypeEntry>> modEntry : byMod.entrySet()) {
|
||||
String modId = modEntry.getKey();
|
||||
List<EntityTypeEntry> entities = modEntry.getValue();
|
||||
|
||||
OptionGroup.Builder groupBuilder = OptionGroup.createBuilder();
|
||||
|
||||
for (EntityTypeEntry entity : entities) {
|
||||
Option<Boolean> option = createEntityOption(entity);
|
||||
if (option != null) {
|
||||
groupBuilder.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
// Only add group if it has options
|
||||
OptionGroup group = groupBuilder.build();
|
||||
if (!group.getOptions().isEmpty()) {
|
||||
groups.add(group);
|
||||
}
|
||||
}
|
||||
|
||||
return new OptionPage(I18n.format("options.dynamiclights.page"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
private static Option<Boolean> createEntityOption(EntityTypeEntry entry) {
|
||||
final String className = entry.getClassName();
|
||||
|
||||
// Resolve class once during option creation, not on every get/set
|
||||
Class<?> resolvedClass;
|
||||
try {
|
||||
resolvedClass = Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Class not loaded, skip this option
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class<?> entityClass = resolvedClass;
|
||||
|
||||
return OptionImpl.createBuilder(Boolean.class, EntityLightConfigStorage.INSTANCE)
|
||||
.setName(entry.getDisplayName() + " (" + entry.getModId() + ")")
|
||||
.setTooltip(I18n.format("options.dynamiclights.entity.tooltip", entry.getDisplayName()))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding(
|
||||
(_, value) -> EntityLightConfig.setEntityTypeEnabled(entityClass, value),
|
||||
storage -> EntityLightConfig.isEntityTypeEnabled(entityClass)
|
||||
)
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.build();
|
||||
return new OptionPage(I18n.format("options.dynamiclights.page"), ImmutableList.of(
|
||||
OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_SHADER_FORCE.option)
|
||||
.build(),
|
||||
OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS_FRUSTUM_CULLING.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_ADAPTIVE_TICKING.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_CULL_TIMEOUT.option)
|
||||
.build(),
|
||||
OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS_SLOW_DIST.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_SLOWER_DIST.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_BACKGROUND_DIST.option)
|
||||
.build(),
|
||||
OptionGroup.createBuilder()
|
||||
.add(new SubScreenOption(I18n.format("options.dynamiclights.entities"), I18n.format("options.dynamiclights.entities.tooltip"), DynamicLightsEntityScreen::new))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@ public final class BopFogColorSource implements BopFogBlend.ColorSource {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void freeWorld() {
|
||||
this.world = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fogColour(int x, int y, int z) {
|
||||
final BiomeGenBase biome = FogBiomeCache.get(world, x, z);
|
||||
|
||||
@@ -9,7 +9,7 @@ public final class FogBiomeCache {
|
||||
private static final int MAX_ENTRIES = 16384;
|
||||
|
||||
private static final Long2ObjectOpenHashMap<BiomeGenBase> CACHE = new Long2ObjectOpenHashMap<>();
|
||||
private static World lastWorld;
|
||||
private static World cachedWorld;
|
||||
private static int generation;
|
||||
|
||||
private FogBiomeCache() {}
|
||||
@@ -18,10 +18,14 @@ public final class FogBiomeCache {
|
||||
return generation;
|
||||
}
|
||||
|
||||
public static void invalidate() {
|
||||
cachedWorld = null;
|
||||
}
|
||||
|
||||
public static BiomeGenBase get(World world, int x, int z) {
|
||||
if (world != lastWorld) {
|
||||
if (world != cachedWorld) {
|
||||
CACHE.clear();
|
||||
lastWorld = world;
|
||||
cachedWorld = world;
|
||||
generation++;
|
||||
}
|
||||
final long key = ((long) x << 32) | (z & 0xFFFFFFFFL);
|
||||
|
||||
@@ -452,6 +452,18 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static GLProfile glProfile;
|
||||
|
||||
@Config.Comment("Enable random top-face texture orientation for configured blocks")
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean enableNaturalTextures = true;
|
||||
|
||||
@Config.Comment("List of block registry names to apply random top-face texture rotation to")
|
||||
@Config.DefaultStringList({
|
||||
"minecraft:andesite", "minecraft:dirt", "minecraft:granite", "minecraft:grass", "minecraft:mycelium", "minecraft:sand", "minecraft:soul_sand", "etfuturum:calcite", "etfuturum:coarse_dirt", "etfuturum:cobbled_deepslate", "etfuturum:concrete_powder", "etfuturum:deepslate", "etfuturum:polished_deepslate", "etfuturum:soul_soil", "etfuturum:tuff", "BiomesOPlenty:ash", "BiomesOPlenty:cragRock", "BiomesOPlenty:driedDirt", "BiomesOPlenty:hardDirt", "BiomesOPlenty:hardSand", "BiomesOPlenty:mud", "BiomesOPlenty:newBopDirt", "Botania:dirtPath", "Botania:enchantedSoil", "Botania:livingrock", "Botania:prismarine", "Botania:shimmerrock", "Botany:loam", "Botany:loamNoWeed", "Botany:soil", "Botany:soilNoWeed", "chisel:moss", "chisel:moss_carpet", "DraconicEvolution:earth", "dreamcraft:SandClayMix", "ExtraUtilities:color_hellsand", "ExtraUtilities:cursedearthside", "GalaxySpace:acentauribbgrunt", "GalaxySpace:acentauribbsubgrunt", "GalaxySpace:barnardaCdirt", "GalaxySpace:barnardaEgrunt", "GalaxySpace:barnardaEsubgrunt", "GalaxySpace:barnardaFgrunt", "GalaxySpace:barnardaFsubgrunt", "GalaxySpace:callistoblocks", "GalaxySpace:ceresblocks", "GalaxySpace:deimosblocks", "GalaxySpace:europagrunt", "GalaxySpace:ganymedeblocks", "GalaxySpace:haumeablocks", "GalaxySpace:ioblocks", "GalaxySpace:makemakegrunt", "GalaxySpace:mercuryblocks", "GalaxySpace:mirandablocks", "GalaxySpace:oberonblocks", "GalaxySpace:phobosblocks", "GalaxySpace:proteusblocks", "GalaxySpace:tcetieblocks", "GalaxySpace:titanblocks", "GalaxySpace:tritonblocks", "GalaxySpace:vegabgrunt", "GalaxySpace:vegabsubgrunt", "GalaxySpace:venusblocks", "gregtech:gt.blockgranites", "IC2:blockBasalt", "MagicBees:magicbees.enchantedEarth", "Natura:heatsand", "RandomThings:fertilizedDirt", "TConstruct:CraftedSoil", "TConstruct:SpeedBlock", "thaumicbases:oldCobble", "thaumicbases:oldCobbleMossy", "ToxicEverglades:blockDarkWorldGround2", "VillageNames:concretePowder", "witchery:pitdirt"
|
||||
})
|
||||
public static String[] naturalTextureBlocks = new String[] {
|
||||
"minecraft:andesite", "minecraft:dirt", "minecraft:granite", "minecraft:grass", "minecraft:mycelium", "minecraft:sand", "minecraft:soul_sand", "etfuturum:calcite", "etfuturum:coarse_dirt", "etfuturum:cobbled_deepslate", "etfuturum:concrete_powder", "etfuturum:deepslate", "etfuturum:polished_deepslate", "etfuturum:soul_soil", "etfuturum:tuff", "BiomesOPlenty:ash", "BiomesOPlenty:cragRock", "BiomesOPlenty:driedDirt", "BiomesOPlenty:hardDirt", "BiomesOPlenty:hardSand", "BiomesOPlenty:mud", "BiomesOPlenty:newBopDirt", "Botania:dirtPath", "Botania:enchantedSoil", "Botania:livingrock", "Botania:prismarine", "Botania:shimmerrock", "Botany:loam", "Botany:loamNoWeed", "Botany:soil", "Botany:soilNoWeed", "chisel:moss", "chisel:moss_carpet", "DraconicEvolution:earth", "dreamcraft:SandClayMix", "ExtraUtilities:color_hellsand", "ExtraUtilities:cursedearthside", "GalaxySpace:acentauribbgrunt", "GalaxySpace:acentauribbsubgrunt", "GalaxySpace:barnardaCdirt", "GalaxySpace:barnardaEgrunt", "GalaxySpace:barnardaEsubgrunt", "GalaxySpace:barnardaFgrunt", "GalaxySpace:barnardaFsubgrunt", "GalaxySpace:callistoblocks", "GalaxySpace:ceresblocks", "GalaxySpace:deimosblocks", "GalaxySpace:europagrunt", "GalaxySpace:ganymedeblocks", "GalaxySpace:haumeablocks", "GalaxySpace:ioblocks", "GalaxySpace:makemakegrunt", "GalaxySpace:mercuryblocks", "GalaxySpace:mirandablocks", "GalaxySpace:oberonblocks", "GalaxySpace:phobosblocks", "GalaxySpace:proteusblocks", "GalaxySpace:tcetieblocks", "GalaxySpace:titanblocks", "GalaxySpace:tritonblocks", "GalaxySpace:vegabgrunt", "GalaxySpace:vegabsubgrunt", "GalaxySpace:venusblocks", "gregtech:gt.blockgranites", "IC2:blockBasalt", "MagicBees:magicbees.enchantedEarth", "Natura:heatsand", "RandomThings:fertilizedDirt", "TConstruct:CraftedSoil", "TConstruct:SpeedBlock", "thaumicbases:oldCobble", "thaumicbases:oldCobbleMossy", "ToxicEverglades:blockDarkWorldGround2", "VillageNames:concretePowder", "witchery:pitdirt"
|
||||
};
|
||||
|
||||
public static void applyGpuCullingMode() {
|
||||
GpuCulling.setMode(gpuCullingMode == null ? GpuCullingMode.CPU_ONLY : gpuCullingMode);
|
||||
}
|
||||
|
||||
+1
-3
@@ -71,7 +71,6 @@ public final class EntityLightConfig {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<EntityTypeEntry> getAllEntityTypes() {
|
||||
List<EntityTypeEntry> entries = new ArrayList<>();
|
||||
Set<String> seenClasses = new HashSet<>();
|
||||
@@ -88,9 +87,8 @@ public final class EntityLightConfig {
|
||||
|
||||
String modId = getModIdForEntity(entityClass, entityId);
|
||||
String displayName = getDisplayName(entityId, entityClass);
|
||||
boolean enabled = !disabledClassNames.contains(className);
|
||||
|
||||
entries.add(new EntityTypeEntry(displayName, className, modId, enabled));
|
||||
entries.add(new EntityTypeEntry(displayName, entityClass, modId));
|
||||
}
|
||||
|
||||
// Sort by mod ID, then by display name
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.dynamiclights.config;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage;
|
||||
|
||||
public class EntityLightConfigStorage implements OptionStorage<EntityLightConfigStorage> {
|
||||
|
||||
public static final EntityLightConfigStorage INSTANCE = new EntityLightConfigStorage();
|
||||
|
||||
private EntityLightConfigStorage() {}
|
||||
|
||||
@Override
|
||||
public EntityLightConfigStorage getData() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
EntityLightConfig.save();
|
||||
}
|
||||
}
|
||||
+20
-15
@@ -1,42 +1,47 @@
|
||||
package com.gtnewhorizons.angelica.dynamiclights.config;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class EntityTypeEntry {
|
||||
private final String displayName;
|
||||
private final String className;
|
||||
private final String modId;
|
||||
private boolean enabled;
|
||||
public final class EntityTypeEntry {
|
||||
|
||||
public EntityTypeEntry(@NotNull String displayName, @NotNull String className, @NotNull String modId, boolean enabled) {
|
||||
private final String displayName;
|
||||
private final Class<?> entityClass;
|
||||
private final String modId;
|
||||
private final String searchName;
|
||||
private final String searchModId;
|
||||
|
||||
public EntityTypeEntry(@NotNull String displayName, @NotNull Class<?> entityClass, @NotNull String modId) {
|
||||
this.displayName = displayName;
|
||||
this.className = className;
|
||||
this.entityClass = entityClass;
|
||||
this.modId = modId;
|
||||
this.enabled = enabled;
|
||||
this.searchName = displayName.toLowerCase(Locale.ROOT);
|
||||
this.searchModId = modId.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
public Class<?> getEntityClass() {
|
||||
return entityClass;
|
||||
}
|
||||
|
||||
public String getModId() {
|
||||
return modId;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
public String getSearchName() {
|
||||
return searchName;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
public String getSearchModId() {
|
||||
return searchModId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName + " (" + modId + ") [" + (enabled ? "ON" : "OFF") + "]";
|
||||
return displayName + " (" + modId + ")";
|
||||
}
|
||||
}
|
||||
+10
@@ -11,6 +11,8 @@ import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHold
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.iris.BlockRenderContext;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.iris.ContextAwareChunkVertexEncoder;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.WorldSlice;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.utils.NaturalTextureUtils;
|
||||
import com.prupe.mcpatcher.mal.block.RenderBlocksUtils;
|
||||
import it.unimi.dsi.fastutil.floats.FloatArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||
@@ -361,8 +363,16 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
setRenderPass(pass);
|
||||
// Trigger side effects from canRenderInPass (some ISBRHs like BuildCraft set global state in this method that gets read elsewhere renderWorldBlock)
|
||||
block.canRenderInPass(pass);
|
||||
|
||||
// Some blocks get randomly rotated top faces
|
||||
final boolean applyNaturalTex = AngelicaConfig.enableNaturalTextures && NaturalTextureUtils.isNaturalBlock(block);
|
||||
if (applyNaturalTex) { renderBlocks.uvRotateTop = NaturalTextureUtils.getTopRotation(x, y, z); }
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
renderBlocks.renderBlockByRenderType(block, x, y, z);
|
||||
|
||||
if (applyNaturalTex) { renderBlocks.uvRotateTop = 0; } // Reset
|
||||
|
||||
boolean blockAllowsSmoothLighting = Minecraft.isAmbientOcclusionEnabled() // smooth lighting on
|
||||
&& block.getLightValue() == 0; // does not emit real block light
|
||||
buildContext.copyRawBuffer(tessellator.rawBuffer, tessellator.vertexCount,
|
||||
|
||||
+4
@@ -6,6 +6,8 @@ import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.bop.BopFogBlend;
|
||||
import com.gtnewhorizons.angelica.compat.bop.FogBiomeCache;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
@@ -166,6 +168,8 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
TesrBatchRenderer.INSTANCE.clearRetained();
|
||||
ModelPartBatcher.INSTANCE.clear();
|
||||
GpuCulling.onWorldUnload();
|
||||
BopFogBlend.invalidate();
|
||||
FogBiomeCache.invalidate();
|
||||
super.unloadWorld();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.gtnewhorizons.angelica.utils;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
|
||||
public class NaturalTextureUtils {
|
||||
|
||||
// Yes this is supposed to be volatile
|
||||
private volatile static Set<Block> cachedWhitelistedBlocks = null;
|
||||
|
||||
public static int getTopRotation(int x, int y, int z) {
|
||||
long hash = (x * 3129871L) ^ (z * 116586811L) ^ y;
|
||||
hash = hash * hash * 42317861L + hash * 11L;
|
||||
return (int) (hash & 3);
|
||||
}
|
||||
|
||||
// This method gets called from worker threads
|
||||
public static boolean isNaturalBlock(Block block) {
|
||||
if (cachedWhitelistedBlocks == null) {
|
||||
// If list is empty add back all the stuff from config
|
||||
initCache();
|
||||
}
|
||||
return cachedWhitelistedBlocks.contains(block);
|
||||
}
|
||||
|
||||
// On reload clear the list
|
||||
public static void reloadCache() {
|
||||
cachedWhitelistedBlocks = null;
|
||||
}
|
||||
|
||||
private static void initCache() {
|
||||
Set<Block> set = new ReferenceOpenHashSet<>();
|
||||
if (AngelicaConfig.naturalTextureBlocks != null) {
|
||||
for (String name : AngelicaConfig.naturalTextureBlocks) {
|
||||
Block b = (Block) Block.blockRegistry.getObject(name);
|
||||
if (b != null && b != Blocks.air) {
|
||||
set.add(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
cachedWhitelistedBlocks = set;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class Zoom {
|
||||
private static long zoomLerpLastNano = 0L;
|
||||
|
||||
@Getter
|
||||
private static final KeyBinding zoomKey = new KeyBinding("Zoom", 0, "key.categories.misc");
|
||||
private static final KeyBinding zoomKey = new KeyBinding("angelica.keybind.zoom", 0, "key.categories.misc");
|
||||
|
||||
private static boolean zoomEnabled = false;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public class CTMUtils {
|
||||
}
|
||||
|
||||
public static void clearCurrentCompact() {
|
||||
CURRENT_COMPACT.remove();
|
||||
CURRENT_COMPACT.set(null);
|
||||
}
|
||||
|
||||
private static final StampedLock lock = new StampedLock();
|
||||
|
||||
@@ -12,9 +12,7 @@ public class NotFineConfig {
|
||||
private static final String CATEGORY_TOGGLE = "toggle";
|
||||
private static final String CATEGORY_UNFINISHED = "unfinished";
|
||||
|
||||
public static boolean allowAdvancedOpenGL;
|
||||
public static boolean allowToggle3DAnaglyph;
|
||||
public static boolean allowToggleFBO;
|
||||
|
||||
public static boolean betterBlockFaceCulling;
|
||||
public static boolean renderPass;
|
||||
@@ -23,12 +21,7 @@ public class NotFineConfig {
|
||||
File configFile = new File(Launch.minecraftHome + File.separator + "config" + File.separator + NotFine.MODID + File.separator + "notfine.cfg");
|
||||
Configuration config = new Configuration(configFile);
|
||||
|
||||
allowAdvancedOpenGL = config.getBoolean("allowAdvancedOpenGL", CATEGORY_GENERAL, false,
|
||||
"Allow Advanced OpenGL to be enabled when it might be supported.");
|
||||
allowToggle3DAnaglyph = config.getBoolean("allowToggle3DAnaglyph", CATEGORY_GENERAL, true,
|
||||
"Allow 3D Anaglyph to be enabled.");
|
||||
allowToggleFBO = config.getBoolean("allowToggleFBO", CATEGORY_GENERAL, false,
|
||||
"Allow FBOs to be disabled.");
|
||||
allowToggle3DAnaglyph = config.getBoolean("allowToggle3DAnaglyph", CATEGORY_GENERAL, true, "Allow 3D Anaglyph to be enabled.");
|
||||
|
||||
config.setCategoryComment(CATEGORY_TOGGLE, "Toggle mod features.");
|
||||
betterBlockFaceCulling = config.getBoolean("betterBlockFaceCulling", CATEGORY_TOGGLE, true,
|
||||
@@ -43,10 +36,7 @@ public class NotFineConfig {
|
||||
config.save();
|
||||
}
|
||||
|
||||
//These will probably break hard with Angelica.
|
||||
//AdvancedOpenGL even breaks hard on its own.
|
||||
allowAdvancedOpenGL = false;
|
||||
allowToggleFBO = false;
|
||||
//This will probably break hard with Angelica.
|
||||
renderPass = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,21 +243,6 @@ public class NotFineGameOptionPages {
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.advancedOpengl"))
|
||||
.setTooltip(I18n.format("sodium.options.advanced_opengl.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.advancedOpengl = value, opts -> opts.advancedOpengl)
|
||||
.setImpact(OptionImpact.VARIES)
|
||||
.setEnabled(NotFineConfig.allowAdvancedOpenGL)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.fboEnable"))
|
||||
.setTooltip(I18n.format("sodium.options.fbo.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.fboEnable = value, opts -> opts.fboEnable)
|
||||
.setEnabled(NotFineConfig.allowToggleFBO)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.anaglyph"))
|
||||
.setTooltip(I18n.format("sodium.options.anaglyph.tooltip"))
|
||||
|
||||
@@ -18,15 +18,9 @@ public class ClientProxy extends CommonProxy {
|
||||
FMLCommonHandler.instance().bus().register(this);
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
|
||||
if(!NotFineConfig.allowAdvancedOpenGL) {
|
||||
Minecraft.getMinecraft().gameSettings.advancedOpengl = false;
|
||||
}
|
||||
if(!NotFineConfig.allowToggle3DAnaglyph) {
|
||||
Minecraft.getMinecraft().gameSettings.anaglyph = false;
|
||||
}
|
||||
if(!NotFineConfig.allowToggleFBO) {
|
||||
Minecraft.getMinecraft().gameSettings.fboEnable = true;
|
||||
}
|
||||
|
||||
for(Settings setting : Settings.values()) {
|
||||
setting.ready();
|
||||
|
||||
+4
-13
@@ -105,9 +105,9 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
final Dim2i applyButtonDim = new Dim2i(tabFrameDim.getLimitX() - 134, tabFrameDim.getLimitY() + 5, 65, 20);
|
||||
final Dim2i closeButtonDim = new Dim2i(tabFrameDim.getLimitX() - 65, tabFrameDim.getLimitY() + 5, 65, 20);
|
||||
|
||||
this.undoButton = new FlatButtonWidget(undoButtonDim, "Undo", this::undoChanges);
|
||||
this.applyButton = new FlatButtonWidget(applyButtonDim, "Apply", this::applyChanges);
|
||||
this.closeButton = new FlatButtonWidget(closeButtonDim, "Close", this::onClose);
|
||||
this.undoButton = new FlatButtonWidget(undoButtonDim, I18n.format("sodium.options.buttons.undo"), this::undoChanges);
|
||||
this.applyButton = new FlatButtonWidget(applyButtonDim, I18n.format("sodium.options.buttons.apply"), this::applyChanges);
|
||||
this.closeButton = new FlatButtonWidget(closeButtonDim, I18n.format("gui.done"), this::onClose);
|
||||
|
||||
// Pre-compute button text and widths to avoid duplicate calculations
|
||||
final String irisText = Iris.enabled ? I18n.format(IrisApi.getInstance().getMainScreenLanguageKey()) : null;
|
||||
@@ -202,16 +202,7 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
}
|
||||
|
||||
private void updateControls() {
|
||||
boolean hasChanges = this.getAllOptions()
|
||||
.anyMatch(Option::hasChanged);
|
||||
|
||||
for (OptionPage page : this.pages) {
|
||||
for (Option<?> option : page.getOptions()) {
|
||||
if (option.hasChanged()) {
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
final boolean hasChanges = this.getAllOptions().anyMatch(Option::hasChanged);
|
||||
|
||||
this.applyButton.setEnabled(hasChanges);
|
||||
this.undoButton.setVisible(hasChanges);
|
||||
|
||||
+1
-5
@@ -93,11 +93,7 @@ public class SearchTextFieldComponent extends AbstractWidget {
|
||||
return;
|
||||
}
|
||||
if (!this.isFocused() && this.text.isEmpty()) {
|
||||
final String key = "rso.search_bar_empty";
|
||||
String text = I18n.format(key);
|
||||
if (text.equals(key))
|
||||
text = "Search options...";
|
||||
this.textRenderer.drawString(text, this.dim.getOriginX() + 6, this.dim.getOriginY() + 6, 0xFFAAAAAA);
|
||||
this.textRenderer.drawString(I18n.format("rso.search_bar_empty"), this.dim.getOriginX() + 6, this.dim.getOriginY() + 6, 0xFFAAAAAA);
|
||||
}
|
||||
|
||||
drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.isFocused() ? 0xE0000000 : 0x90000000);
|
||||
|
||||
@@ -303,9 +303,10 @@ public class SodiumGameOptionPages {
|
||||
.add(OptionImpl.createBuilder(StreamingUploader.UploadStrategy.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.upload_method.name"))
|
||||
.setTooltip(I18n.format("sodium.options.upload_method.tooltip"))
|
||||
.setControl(o ->
|
||||
new CyclingControl<>(o, StreamingUploader.UploadStrategy.class, StreamingUploader.UploadStrategy.values())
|
||||
)
|
||||
.setControl(o -> new CyclingControl<>(o, StreamingUploader.UploadStrategy.class, new String[]{
|
||||
I18n.format("sodium.options.upload_method.buffer_data"),
|
||||
I18n.format("sodium.options.upload_method.buffer_subdata"),
|
||||
I18n.format("sodium.options.upload_method.map_buffer") }))
|
||||
.setBinding((opts, value) -> opts.advanced.streamingUploadStrategy = value, opts -> opts.advanced.streamingUploadStrategy)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setImpact(OptionImpact.VARIES)
|
||||
@@ -409,7 +410,10 @@ public class SodiumGameOptionPages {
|
||||
.add(OptionImpl.createBuilder(AsyncOcclusionMode.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.async_occlusion_mode.name"))
|
||||
.setTooltip(I18n.format("sodium.options.async_occlusion_mode.tooltip"))
|
||||
.setControl(o -> new CyclingControl<>(o, AsyncOcclusionMode.class, new String[]{"None", "Only Shadow", "Everything"}))
|
||||
.setControl(o -> new CyclingControl<>(o, AsyncOcclusionMode.class, new String[]{
|
||||
I18n.format("sodium.options.async_occlusion_mode.none"),
|
||||
I18n.format("sodium.options.async_occlusion_mode.only_shadow"),
|
||||
I18n.format("sodium.options.async_occlusion_mode.everything") }))
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> opts.performance.asyncOcclusionMode = value, opts -> opts.performance.asyncOcclusionMode)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
|
||||
@@ -54,7 +54,6 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen {
|
||||
|
||||
protected OptionPage shaderPacks;
|
||||
|
||||
|
||||
public SodiumOptionsGUI(GuiScreen prevScreen) {
|
||||
this.prevScreen = prevScreen;
|
||||
|
||||
@@ -67,10 +66,7 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen {
|
||||
|
||||
// Add Dynamic Lights page if enabled
|
||||
if (DynamicLights.configEnabled) {
|
||||
var dlPage = DynamicLightsOptionPages.dynamicLights();
|
||||
if (dlPage != null) {
|
||||
this.pages.add(dlPage);
|
||||
}
|
||||
this.pages.add(DynamicLightsOptionPages.dynamicLights());
|
||||
}
|
||||
|
||||
if (Iris.enabled) {
|
||||
@@ -194,15 +190,7 @@ public class SodiumOptionsGUI extends ScrollableGuiScreen {
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
boolean hasChanges = this.getAllOptions().anyMatch(Option::hasChanged);
|
||||
|
||||
for (OptionPage page : this.pages) {
|
||||
for (Option<?> option : page.getOptions()) {
|
||||
if (option.hasChanged()) {
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
final boolean hasChanges = this.getAllOptions().anyMatch(Option::hasChanged);
|
||||
|
||||
this.applyButton.setEnabled(hasChanges);
|
||||
this.undoButton.setVisible(hasChanges);
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package me.jellysquid.mods.sodium.client.gui.options;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.Control;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.element.SodiumControlElement;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
|
||||
/** "Option" that opens a sub screen */
|
||||
public class SubScreenOption implements Option<Void> {
|
||||
|
||||
private static final int ARROW_HOVERED = 0xFF94E4D3;
|
||||
private static final int ARROW_IDLE = 0xFFAAAAAA;
|
||||
private static final String ARROW = ">";
|
||||
|
||||
private static final OptionStorage<Void> NO_STORAGE = new OptionStorage<Void>() {
|
||||
|
||||
@Override
|
||||
public Void getData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {}
|
||||
};
|
||||
|
||||
private final String name;
|
||||
private final String tooltip;
|
||||
private final Function<GuiScreen, GuiScreen> destination;
|
||||
private final Control<Void> control = new SubScreenControl(this);
|
||||
|
||||
public SubScreenOption(String name, String tooltip, Function<GuiScreen, GuiScreen> destination) {
|
||||
this.name = name;
|
||||
this.tooltip = tooltip;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
private void open() {
|
||||
final var mc = Minecraft.getMinecraft();
|
||||
mc.displayGuiScreen(this.destination.apply(mc.currentScreen));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltip() {
|
||||
return this.tooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionImpact getImpact() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Control<Void> getControl() {
|
||||
return this.control;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@Override
|
||||
public void reset() {}
|
||||
|
||||
@Override
|
||||
public OptionStorage<?> getStorage() {
|
||||
return NO_STORAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChanged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyChanges() {}
|
||||
|
||||
@Override
|
||||
public Collection<OptionFlag> getFlags() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
private record SubScreenControl(SubScreenOption target) implements Control<Void> {
|
||||
|
||||
@Override
|
||||
public Option<Void> getOption() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlElement<Void> createElement(Dim2i dim, ControlElementFactory factory) {
|
||||
return new SubScreenElement(this.target, dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxWidth() {
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SubScreenElement extends SodiumControlElement<Void> {
|
||||
|
||||
private final SubScreenOption target;
|
||||
|
||||
SubScreenElement(SubScreenOption option, Dim2i dim) {
|
||||
super(option, dim);
|
||||
this.target = option;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float delta) {
|
||||
super.render(mouseX, mouseY, delta);
|
||||
|
||||
final var width = this.font.getStringWidth(ARROW);
|
||||
this.drawString(ARROW, this.dim.getLimitX() - width - 6, this.dim.getCenterY() - 4, this.hovered ? ARROW_HOVERED : ARROW_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if (button != 0 || !this.dim.containsCursor(mouseX, mouseY)) return false;
|
||||
|
||||
this.playClickSound();
|
||||
this.target.open();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,11 +343,11 @@ public class Iris {
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
try {
|
||||
reload();
|
||||
if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText("Shaders Reloaded!"));
|
||||
if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText(I18n.format("iris.shaders.reloaded")));
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error while reloading Shaders for Iris!", e);
|
||||
if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText( "Failed tgo reload shaders! Reason: " + Throwables.getRootCause(e).getMessage()));
|
||||
if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText(I18n.format("iris.shaders.reloaded.failure", Throwables.getRootCause(e).getMessage())));
|
||||
}
|
||||
} else if (toggleShadersKeybind.isPressed()) {
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
@@ -356,7 +356,7 @@ public class Iris {
|
||||
} catch (Exception e) {
|
||||
logger.error("Error while toggling shaders!", e);
|
||||
|
||||
if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText( "Failed tgo toggle shaders! Reason: " + Throwables.getRootCause(e).getMessage()));
|
||||
if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText(I18n.format("iris.shaders.toggled.failure", Throwables.getRootCause(e).getMessage())));
|
||||
setShadersDisabled();
|
||||
fallback = true;
|
||||
}
|
||||
@@ -974,9 +974,9 @@ public class Iris {
|
||||
|
||||
public void fmlInitEvent() {
|
||||
IRIS_VERSION = Tags.VERSION;
|
||||
reloadKeybind = new KeyBinding("Reload Shaders", 0, "Iris Keybinds");
|
||||
toggleShadersKeybind = new KeyBinding("Toggle Shaders", 0, "Iris Keybinds");
|
||||
shaderpackScreenKeybind = new KeyBinding("Shaderpack Selection Screen", 0, "Iris Keybinds");
|
||||
reloadKeybind = new KeyBinding("iris.keybind.reload", 0, "key.category.iris.keybinds");
|
||||
toggleShadersKeybind = new KeyBinding("iris.keybind.toggleShaders", 0, "key.category.iris.keybinds");
|
||||
shaderpackScreenKeybind = new KeyBinding("iris.keybind.shaderPackSelection", 0, "key.category.iris.keybinds");
|
||||
|
||||
ClientRegistry.registerKeyBinding(reloadKeybind);
|
||||
ClientRegistry.registerKeyBinding(toggleShadersKeybind);
|
||||
|
||||
@@ -101,13 +101,18 @@ sodium.options.use_no_error_context.name=No Error Context
|
||||
sodium.options.use_no_error_context.tooltip=If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes.
|
||||
sodium.options.async_occlusion_mode.name=Async Occlusion
|
||||
sodium.options.async_occlusion_mode.tooltip=Controls which render passes use asynchronous occlusion culling. ONLY_SHADOW (default) runs async occlusion only for the shadow pass, keeping the main render list synchronous. EVERYTHING runs all passes async, which may cause 1-frame visibility lag during fast camera movement. NONE disables async occlusion entirely.
|
||||
sodium.options.async_occlusion_mode.none=None
|
||||
sodium.options.async_occlusion_mode.only_shadow=Only Shadow
|
||||
sodium.options.async_occlusion_mode.everything=Everything
|
||||
sodium.options.use_occlusion_culling.name=Occlusion Culling
|
||||
sodium.options.use_occlusion_culling.tooltip=If enabled, chunks that are hidden behind other chunks will not be rendered. Disabling this will significantly reduce performance but can be useful for debugging.
|
||||
sodium.options.threads.value=%s thread(s)
|
||||
sodium.options.default=Default
|
||||
sodium.options.buttons.undo=Undo
|
||||
sodium.options.buttons.apply=Apply
|
||||
sodium.options.buttons.donate=Buy coffee for JellySquid!
|
||||
sodium.options.anaglyph.tooltip=If enabled, the world will be rendered twice with red/cyan color masks.
|
||||
sodium.options.show_cape.tooltip=If enabled, your cape will be shown.
|
||||
rso.search_bar_empty=Search options...
|
||||
|
||||
options.dynamic_fov=Dynamic FOV
|
||||
options.dynamic_fov.tooltip=If enabled, the game's field of view will change based on the player's speed.
|
||||
@@ -115,6 +120,15 @@ options.framerate=%s FPS
|
||||
|
||||
iris.shaders.toggled=Toggled shaders to %s!
|
||||
iris.shaders.disabled=Shaders disabled!
|
||||
iris.shaders.reloaded=Shaders Reloaded!
|
||||
iris.shaders.reloaded.failure=Failed to reload shaders! Reason: %s
|
||||
iris.shaders.toggled.failure=Failed to toggle shaders! Reason: %s
|
||||
|
||||
key.category.iris.keybinds=Iris Keybinds
|
||||
iris.keybind.reload=Reload Shaders
|
||||
iris.keybind.toggleShaders=Toggle Shaders
|
||||
iris.keybind.shaderPackSelection=Shaderpack Selection Screen
|
||||
angelica.keybind.zoom=Zoom
|
||||
|
||||
options.iris.apply=Apply
|
||||
options.iris.refresh=Refresh
|
||||
@@ -176,10 +190,14 @@ options.dynamic_lights_cull_timeout=Culling Timeout (ticks)
|
||||
options.dynamic_lights_cull_timeout.tooltip=Maximum ticks a hidden chunk can wait before being forced to rebuild. Lower = more responsive but more GPU work.
|
||||
options.dynamiclights.page=Dynamic Lights
|
||||
options.dynamiclights.entities=Configure Entities...
|
||||
options.dynamiclights.entities.tooltip=Choose which entity types emit dynamic light.
|
||||
options.dynamiclights.entities.title=Dynamic Lights - Entities
|
||||
options.dynamiclights.entities.info=Toggle which entity types emit dynamic light. Some entries are for mod compatibility.
|
||||
options.dynamiclights.entities.search=Search (@mod, $on, $off)
|
||||
options.dynamiclights.entity.tooltip=Toggle dynamic lighting for %s entities. Disable to improve performance if this entity type emits unwanted lights.
|
||||
options.dynamiclights.entities.enableall=Enable All
|
||||
options.dynamiclights.entities.disableall=Disable All
|
||||
options.dynamiclights.entities.enableshown=Enable Shown
|
||||
options.dynamiclights.entities.disableshown=Disable Shown
|
||||
|
||||
options.angelica.search.no_results=No matching options
|
||||
options.angelica.fontconfig=Font Configuration...
|
||||
|
||||
@@ -161,7 +161,6 @@ options.dynamiclights.entities=エンティティの設定...
|
||||
options.dynamiclights.entities.title=ダイナミックライト- エンティティ
|
||||
options.dynamiclights.entities.info=ダイナミックライトを適用するエンティティの種類を設定します。一部の項目はMODとの互換性のために設定されています。
|
||||
options.dynamiclights.entities.search=検索 (@mod, $on, $off)
|
||||
options.dynamiclights.entity.tooltip=%sのエンティティのダイナミックライトを設定します。そのエンティティタイプが不要な光を発する場合は、パフォーマンス向上のために無効にしてください。
|
||||
|
||||
options.angelica.search.no_results=該当する設定が見つかりません
|
||||
options.angelica.fontconfig=フォント設定...
|
||||
|
||||
@@ -164,7 +164,6 @@ options.dynamiclights.entities=配置实体……
|
||||
options.dynamiclights.entities.title=动态光源 - 实体
|
||||
options.dynamiclights.entities.info=切换哪些实体类型发射动态光。部分条目用于模组兼容性。
|
||||
options.dynamiclights.entities.search=搜索(@模组, $开启, $关闭)
|
||||
options.dynamiclights.entity.tooltip=切换 %s 实体的动态光照。如果此类型实体产生不必要光照,禁用以提升性能。
|
||||
|
||||
options.angelica.search.no_results=无匹配选项
|
||||
options.angelica.fontconfig=字体配置...
|
||||
|
||||
@@ -77,6 +77,7 @@ options.total_stars.tooltip=Star Density
|
||||
options.void_fog=Void Fog
|
||||
options.void_fog.tooltip=Void Fog
|
||||
options.hurt_shake=Hurt Screen Shake
|
||||
options.hurt_shake.tooltip=How strongly the camera tilts when you take damage.
|
||||
options.background.random=Random
|
||||
options.zoom_smooth=Smooth Zoom
|
||||
options.zoom_smooth.tooltip=Smoothly interpolates the camera toward the zoom level instead of snapping instantly.
|
||||
|
||||
+1
@@ -52,6 +52,7 @@ public class MixinFogHandlerBiomeCache {
|
||||
final float[] sums = angelica$sums;
|
||||
BopFogBlend.accumulate(world, FogBiomeCache.generation(), BopFogColorSource.INSTANCE.forWorld(world),
|
||||
playerEntity.posX, playerEntity.posZ, playerX, playerY, playerZ, distance, sums);
|
||||
BopFogColorSource.INSTANCE.freeWorld();
|
||||
|
||||
float rBiomeFog = sums[0];
|
||||
float gBiomeFog = sums[1];
|
||||
|
||||
Reference in new issue
Block a user