Fix texture filtering sampling regression (#2115)

This commit is contained in:
Eclipse-Sol authored and GitHub committed 2026-09-19 10:12:14 -07:00
1 parent b6a4497fb3
commit ef68af5850
8 files changed
+67 -9

No files matched your search

@@ -0,0 +1,12 @@
package com.gtnewhorizons.angelica.glsm;
import org.lwjgl.opengl.OpenGLException;
final class GLErrorReporter {
private GLErrorReporter() {}
static void reportError(int error) {
throw new OpenGLException(error);
}
}
@@ -5400,7 +5400,7 @@ public class GLStateManager {
public static void checkGLError() {
final int error = glGetError();
if (error != GL11.GL_NO_ERROR) throw new org.lwjgl.opengl.OpenGLException(error);
if (error != GL11.GL_NO_ERROR) GLErrorReporter.reportError(error);
}
public static String glGetString(int pname) {
@@ -202,6 +202,10 @@ class AngelicaChunkRenderer extends DefaultChunkRenderer {
}
private void bindTerrainSampler() {
if (!SodiumGameOptions.usesTerrainTexelSnap()) {
return;
}
final int anisotropy = SodiumGameOptions.resolvedAnisotropicFiltering();
final boolean nearest = ClientProxy.options().quality.texelSampling.isNearest();
@@ -30,13 +30,20 @@ public class AngelicaRenderPassConfiguration {
.vertexType(vertexType)
.primitiveType(QuadPrimitiveType.TRIANGULATED);
final int mipmapLevels = SodiumGameOptions.terrainMipmapLevels();
if (rgssEnabled) {
builder.extraDefine("USE_RGSS", "");
}
if (SodiumGameOptions.usesTerrainTexelSnap()) {
builder.extraDefine("USE_TEXEL_SNAP", "");
}
if (SodiumGameOptions.effectiveTextureFilterMode().usesAnisotropy()) {
builder.extraDefine("USE_ANISOTROPIC", "");
builder.extraDefine("TERRAIN_GUTTER",
SpritePadding.gutterFor(SodiumGameOptions.terrainMipmapLevels(), true) + ".0");
builder.extraDefine("TERRAIN_GUTTER", SpritePadding.gutterFor(mipmapLevels, true) + ".0");
}
if (mipmapLevels <= 0) {
builder.extraDefine("TERRAIN_NO_MIPS", "");
}
return builder;
@@ -2,6 +2,7 @@ package me.jellysquid.mods.sodium.client.gui;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
@@ -202,6 +203,10 @@ public class SodiumGameOptionPages {
.setBinding((opts, value) -> opts.quality.texelSampling = value,
opts -> opts.quality.texelSampling)
.setImpact(OptionImpact.LOW)
// Only this mode needs a rerender
.setFlags(() -> textureFilterMode.getValue() == TextureFilterMode.NONE
? EnumSet.of(OptionFlag.REQUIRES_RENDERER_RELOAD)
: EnumSet.noneOf(OptionFlag.class))
.build();
groups.add(OptionGroup.createBuilder()
@@ -80,6 +80,11 @@ public class SodiumGameOptions {
return resolveFilterMode(ClientProxy.options().quality.textureFilterMode);
}
public static boolean usesTerrainTexelSnap() {
return effectiveTextureFilterMode() != TextureFilterMode.NONE
|| !ClientProxy.options().quality.texelSampling.isNearest();
}
public static TextureFilterMode resolveFilterMode(TextureFilterMode mode) {
if (mode == null) {
mode = TextureFilterMode.RGSS_ANISOTROPIC;
@@ -16,6 +16,7 @@ import java.util.EnumSet;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Supplier;
public class OptionImpl<S, T> implements OptionExtended<T> {
private final OptionStorage<S> storage;
@@ -23,7 +24,7 @@ public class OptionImpl<S, T> implements OptionExtended<T> {
private final OptionBinding<S, T> binding;
private final Control<T> control;
private final EnumSet<OptionFlag> flags;
private final Supplier<EnumSet<OptionFlag>> flags;
private final String name;
private final String tooltip;
@@ -41,7 +42,7 @@ public class OptionImpl<S, T> implements OptionExtended<T> {
String tooltip,
OptionBinding<S, T> binding,
Function<OptionImpl<S, T>, Control<T>> control,
EnumSet<OptionFlag> flags,
Supplier<EnumSet<OptionFlag>> flags,
OptionImpact impact,
boolean enabled) {
this.storage = storage;
@@ -121,7 +122,7 @@ public class OptionImpl<S, T> implements OptionExtended<T> {
@Override
public Collection<OptionFlag> getFlags() {
return this.flags;
return this.flags.get();
}
public static <S, T> OptionImpl.Builder<S, T> createBuilder(Class<T> type, OptionStorage<S> storage) {
@@ -136,6 +137,7 @@ public class OptionImpl<S, T> implements OptionExtended<T> {
private Function<OptionImpl<S, T>, Control<T>> control;
private OptionImpact impact;
private final EnumSet<OptionFlag> flags = EnumSet.noneOf(OptionFlag.class);
private Supplier<EnumSet<OptionFlag>> flagsSupplier = () -> this.flags;
private boolean enabled = true;
private Builder(OptionStorage<S> storage) {
@@ -202,13 +204,21 @@ public class OptionImpl<S, T> implements OptionExtended<T> {
return this;
}
public Builder<S, T> setFlags(Supplier<EnumSet<OptionFlag>> flags) {
Validate.notNull(flags, "Flags supplier must not be null");
this.flagsSupplier = flags;
return this;
}
public OptionImpl<S, T> build() {
Validate.notNull(this.name, "Name must be specified");
Validate.notNull(this.tooltip, "Tooltip must be specified");
Validate.notNull(this.binding, "Option binding must be specified");
Validate.notNull(this.control, "Control must be specified");
return new OptionImpl<>(this.storage, this.name, this.tooltip, this.binding, this.control, this.flags, this.impact, this.enabled);
return new OptionImpl<>(this.storage, this.name, this.tooltip, this.binding, this.control, this.flagsSupplier, this.impact, this.enabled);
}
}
@@ -68,13 +68,18 @@ float footprintScale(vec2 du, vec2 dv, vec2 texelSize, float limitTexels) {
#endif
vec4 sampleTexelSnapped(sampler2D tex, vec2 uv, vec2 texelSize, vec2 du, vec2 dv, vec2 texelsPerPixel) {
vec2 snapped = snapToTexelCentre(uv, texelSize, texelsPerPixel);
#if defined(TERRAIN_NO_MIPS) && !defined(USE_ANISOTROPIC)
return textureLod(tex, snapped, 0.0);
#else
float gradientScale = exp2(v_MaterialMipBias);
#ifdef USE_ANISOTROPIC
gradientScale *= footprintScale(du * gradientScale, dv * gradientScale, texelSize, TERRAIN_GUTTER);
#endif
return textureGrad(tex, snapToTexelCentre(uv, texelSize, texelsPerPixel),
du * gradientScale, dv * gradientScale);
return textureGrad(tex, snapped, du * gradientScale, dv * gradientScale);
#endif
}
vec4 sampleTexelSnapped(sampler2D tex, vec2 uv, vec2 texelSize) {
@@ -132,6 +137,12 @@ vec4 sampleRGSS(sampler2D tex, vec2 uv, vec2 texelSize) {
for (int i = 0; i < 4; i++) {
rgss += textureGrad(tex, uv + RGSS_OFFSETS[i].x * spreadU + RGSS_OFFSETS[i].y * spreadV, gradU, gradV);
}
#elif defined(TERRAIN_NO_MIPS)
const float lod = 0.0;
for (int i = 0; i < 4; i++) {
rgss += textureLod(tex, uv + RGSS_OFFSETS[i] * texelSize, lod);
}
#else
float duLength = length(du / texelSize);
float dvLength = length(dv / texelSize);
@@ -152,12 +163,16 @@ vec4 sampleRGSS(sampler2D tex, vec2 uv, vec2 texelSize) {
#endif
void main() {
#ifdef USE_TEXEL_SNAP
vec2 texelSize = 1.0 / vec2(textureSize(u_BlockTex, 0));
#ifdef USE_RGSS
vec4 diffuseColor = sampleRGSS(u_BlockTex, v_TexCoord, texelSize);
#else
vec4 diffuseColor = sampleTexelSnapped(u_BlockTex, v_TexCoord, texelSize);
#endif
#else
vec4 diffuseColor = texture(u_BlockTex, v_TexCoord, v_MaterialMipBias);
#endif
#ifdef USE_FRAGMENT_DISCARD
if (diffuseColor.a < v_MaterialAlphaCutoff) {