This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-08-15 14:32:50 -07:00
1 parent ffe54f61b9
commit 69aed42b89
4 files changed
+116 -79

No files matched your search

@@ -70,9 +70,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
private static MultiPhaseParameters.Builder tesrMaterialPhases(ResourceLocation texture, TesrMaterial material) {
final MultiPhaseParameters.Builder b = MultiPhaseParameters.builder();
if (texture != null) {
b.texture(new RenderPhase.Texture(texture, false, false));
}
b.texture(texture != null ? new RenderPhase.Texture(texture, false, false) : NO_TEXTURE);
if (material.isNoCull()) {
b.cull(DISABLE_CULLING);
}
@@ -85,18 +83,14 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
if (material.isDepthOnly()) {
b.writeMaskState(DEPTH_MASK);
}
if (material.cutoutAlpha() > 0) {
b.alpha(new RenderPhase.Alpha(material.cutoutAlpha()));
}
if (material.isDepthEqual()) {
b.depthTest(EQUAL_DEPTH_TEST);
}
b.alpha(material.cutoutAlpha() > 0 ? new RenderPhase.Alpha(material.cutoutAlpha()) : ZERO_ALPHA);
b.depthTest(material.isDepthEqual() ? EQUAL_DEPTH_TEST : LEQUAL_DEPTH_TEST);
switch (material.transparency()) {
case TRANSLUCENT -> b.transparency(TRANSLUCENT_TRANSPARENCY);
case ADDITIVE -> b.transparency(ADDITIVE_TRANSPARENCY);
case ADDITIVE_ALPHA -> b.transparency(LIGHTNING_TRANSPARENCY);
case GLINT -> b.transparency(GLINT_TRANSPARENCY);
case OPAQUE -> {}
case OPAQUE -> b.transparency(NO_TRANSPARENCY);
}
switch (material.special()) {
case GLINT -> b.shader(SPECIAL_GLINT);
@@ -119,21 +113,12 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
GbufferPrograms::teardownSpecialRenderCondition);
public static RenderLayer tesr(ResourceLocation texture, TesrMaterial material) {
final MultiPhaseParameters.Builder b = tesrMaterialPhases(texture, material).shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP);
if (material.transparency() == TesrMaterial.Transparency.TRANSLUCENT) {
b.target(TRANSLUCENT_TARGET);
}
final MultiPhaseParameters.Builder b = tesrMaterialPhases(texture, material).shadeModel(SMOOTH_SHADE_MODEL);
final boolean sortsTranslucent = material.transparency() != TesrMaterial.Transparency.OPAQUE;
return of("angelica_tesr_" + material.transparency().name().toLowerCase(Locale.ROOT),
BatchVertexFormats.POSITION_COLOR_TEXTURE_LIGHTF_NORMAL, GL11.GL_QUADS, 65536, true, sortsTranslucent, b.build(false));
}
public static RenderLayer tesrNoPass(ResourceLocation texture, TesrMaterial material) {
return of("angelica_tesr_nopass_" + material.transparency().name().toLowerCase(Locale.ROOT),
BatchVertexFormats.POSITION_COLOR_TEXTURE_LIGHTF_NORMAL, GL11.GL_QUADS, 65536, true, false,
tesrMaterialPhases(texture, material).build(false));
}
public static RenderLayer getOutline(ResourceLocation texture, RenderPhase.Cull cull) {
return of("outline", DefaultVertexFormat.POSITION_COLOR_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).cull(cull).depthTest(ALWAYS_DEPTH_TEST).alpha(ONE_TENTH_ALPHA).fog(NO_FOG).target(OUTLINE_TARGET).build(RenderLayer.OutlineMode.IS_OUTLINE));
}
@@ -154,7 +139,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
@Override
public TransparencyType getTransparencyType() {
return phases.transparency.getTransparencyType();
return phases.transparency == null ? TransparencyType.OPAQUE : phases.transparency.getTransparencyType();
}
private MultiPhase(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, MultiPhaseParameters phases) {
@@ -170,7 +155,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
}
});
this.phases = phases;
this.affectedOutline = phases.outlineMode == RenderLayer.OutlineMode.AFFECTS_OUTLINE ? phases.texture.getId().map((arg2) -> {
this.affectedOutline = phases.outlineMode == RenderLayer.OutlineMode.AFFECTS_OUTLINE && phases.texture != null ? phases.texture.getId().map((arg2) -> {
return getOutline(arg2, phases.cull);
}) : Optional.empty();
this.hash = Objects.hash(new Object[]{super.hashCode(), phases});
@@ -187,7 +172,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
@Override
public ResourceLocation getTextureId() {
return phases.texture.getId().orElse(null);
return phases.texture == null ? null : phases.texture.getId().orElse(null);
}
@Override
@@ -223,7 +208,9 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
if (arg == arg2) {
return true;
} else {
return arg != null && arg2 != null ? Objects.equals(arg.phases, arg2.phases) : false;
return arg != null && arg2 != null && arg.name.equals(arg2.name)
&& arg.getVertexFormat() == arg2.getVertexFormat() && arg.getDrawMode() == arg2.getDrawMode()
&& Objects.equals(arg.phases, arg2.phases);
}
}
}
@@ -263,7 +250,13 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
this.writeMaskState = writeMaskState;
this.shader = shader;
this.outlineMode = outlineMode;
this.phases = ImmutableList.of(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.fog, this.layering, this.target, this.texturing, this.writeMaskState, this.shader);
final ImmutableList.Builder<RenderPhase> declared = ImmutableList.builder();
for (RenderPhase phase : new RenderPhase[] { this.texture, this.transparency, this.diffuseLighting,
this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.fog, this.layering,
this.target, this.texturing, this.writeMaskState, this.shader }) {
if (phase != null) declared.add(phase);
}
this.phases = declared.build();
}
@Override
@@ -308,22 +301,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
private RenderPhase.WriteMaskState writeMaskState;
private RenderPhase.Shader shader;
private Builder() {
this.texture = RenderPhase.NO_TEXTURE ;
this.transparency = RenderPhase.NO_TRANSPARENCY;
this.diffuseLighting = RenderPhase.DISABLE_DIFFUSE_LIGHTING;
this.shadeModel = RenderPhase.SHADE_MODEL;
this.alpha = RenderPhase.ZERO_ALPHA;
this.depthTest = RenderPhase.LEQUAL_DEPTH_TEST;
this.cull = RenderPhase.ENABLE_CULLING;
this.lightmap = RenderPhase.DISABLE_LIGHTMAP;
this.fog = RenderPhase.FOG;
this.layering = RenderPhase.NO_LAYERING;
this.target = RenderPhase.MAIN_TARGET;
this.texturing = RenderPhase.DEFAULT_TEXTURING;
this.writeMaskState = RenderPhase.ALL_MASK;
this.shader = RenderPhase.NO_SHADER;
}
private Builder() {}
public Builder texture(RenderPhase.Texture texture) {
this.texture = texture;
@@ -158,9 +158,8 @@ public final class TesrBatchRenderer {
boolean depthEqual;
TesrMaterial.SpecialRender special;
TesrShader shader;
boolean noPass;
LayerKey set(ResourceLocation texture, TesrMaterial.Transparency transparency, boolean noCull, boolean unlit, boolean noDepthWrite, boolean depthOnly, float cutoutAlpha, boolean depthEqual, TesrMaterial.SpecialRender special, TesrShader shader, boolean noPass) {
LayerKey set(ResourceLocation texture, TesrMaterial.Transparency transparency, boolean noCull, boolean unlit, boolean noDepthWrite, boolean depthOnly, float cutoutAlpha, boolean depthEqual, TesrMaterial.SpecialRender special, TesrShader shader) {
this.texture = texture;
this.transparency = transparency;
this.noCull = noCull;
@@ -171,12 +170,11 @@ public final class TesrBatchRenderer {
this.depthEqual = depthEqual;
this.special = special;
this.shader = shader;
this.noPass = noPass;
return this;
}
LayerKey copy() {
return new LayerKey().set(texture, transparency, noCull, unlit, noDepthWrite, depthOnly, cutoutAlpha, depthEqual, special, shader, noPass);
return new LayerKey().set(texture, transparency, noCull, unlit, noDepthWrite, depthOnly, cutoutAlpha, depthEqual, special, shader);
}
@Override
@@ -186,7 +184,7 @@ public final class TesrBatchRenderer {
&& noCull == other.noCull && unlit == other.unlit && noDepthWrite == other.noDepthWrite
&& depthOnly == other.depthOnly
&& Float.floatToIntBits(cutoutAlpha) == Float.floatToIntBits(other.cutoutAlpha)
&& depthEqual == other.depthEqual && special == other.special && shader == other.shader && noPass == other.noPass;
&& depthEqual == other.depthEqual && special == other.special && shader == other.shader;
}
@Override
@@ -201,7 +199,6 @@ public final class TesrBatchRenderer {
h = h * 31 + (depthEqual ? 1 : 0);
h = h * 31 + Objects.hashCode(special);
h = h * 31 + System.identityHashCode(shader);
h = h * 31 + (noPass ? 1 : 0);
return h;
}
}
@@ -211,37 +208,23 @@ public final class TesrBatchRenderer {
private ResourceLocation lastLayerTexture;
private TesrMaterial lastLayerMaterial;
private RenderLayer lastLayer;
private ResourceLocation lastImmediateTexture;
private TesrMaterial lastImmediateMaterial;
private RenderLayer lastImmediateLayer;
private RenderLayer layerFor(ResourceLocation texture, TesrMaterial material) {
if (texture == lastLayerTexture && material == lastLayerMaterial) {
return lastLayer;
}
final RenderLayer layer = layerLookup(texture, material, false);
final RenderLayer layer = layerLookup(texture, material);
lastLayerTexture = texture;
lastLayerMaterial = material;
lastLayer = layer;
return layer;
}
private RenderLayer noPassLayerFor(ResourceLocation texture, TesrMaterial material) {
if (texture == lastImmediateTexture && material == lastImmediateMaterial) {
return lastImmediateLayer;
}
final RenderLayer layer = layerLookup(texture, material, true);
lastImmediateTexture = texture;
lastImmediateMaterial = material;
lastImmediateLayer = layer;
return layer;
}
private RenderLayer layerLookup(ResourceLocation texture, TesrMaterial material, boolean noPass) {
final LayerKey key = scratchKey.set(texture, material.transparency(), material.isNoCull(), material.isUnlit(), material.isNoDepthWrite(), material.isDepthOnly(), material.cutoutAlpha(), material.isDepthEqual(), material.special(), material.shader(), noPass);
private RenderLayer layerLookup(ResourceLocation texture, TesrMaterial material) {
final LayerKey key = scratchKey.set(texture, material.transparency(), material.isNoCull(), material.isUnlit(), material.isNoDepthWrite(), material.isDepthOnly(), material.cutoutAlpha(), material.isDepthEqual(), material.special(), material.shader());
RenderLayer layer = layers.get(key);
if (layer == null) {
layer = noPass ? RenderLayer.tesrNoPass(texture, material) : RenderLayer.tesr(texture, material);
layer = RenderLayer.tesr(texture, material);
layers.put(key.copy(), layer);
}
return layer;
@@ -469,7 +452,7 @@ public final class TesrBatchRenderer {
final long end = VertexTransform.writeInstance(addr, format, template, identity, scratchVec, colorABGR, packedLight, null);
immediateScratch.position((int) (end - addr));
immediateScratch.flip();
final RenderLayer layer = noPassLayerFor(texture, material);
final RenderLayer layer = layerFor(texture, material);
GLStateManager.glPushAttrib(AngelicaBufferSource.SAVED_STATE_BITS);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
layer.startDrawing();
@@ -18,43 +18,41 @@ class TesrLayerKeyTest {
@Test
void scratchProbeMatchesCopiedKey() {
final TesrBatchRenderer.LayerKey scratch = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER, false);
final TesrBatchRenderer.LayerKey scratch = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER);
final TesrBatchRenderer.LayerKey stored = scratch.copy();
assertNotSame(scratch, stored);
assertEquals(scratch, stored);
assertEquals(scratch.hashCode(), stored.hashCode());
scratch.set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER, false);
scratch.set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER);
assertEquals(stored, scratch, "re-set scratch still matches stored copy");
}
@Test
void fieldChangesBreakEquality() {
final TesrBatchRenderer.LayerKey base = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false);
final TesrBatchRenderer.LayerKey base = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null);
final TesrBatchRenderer.LayerKey other = base.copy();
other.set(null, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false);
other.set(null, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.TRANSLUCENT, false, false, false, false, 0f, false, NONE, null, false);
other.set(TEX, TesrMaterial.Transparency.TRANSLUCENT, false, false, false, false, 0f, false, NONE, null);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0.5f, false, NONE, null, false);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0.5f, false, NONE, null);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, true, 0f, false, NONE, null, false);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, true, 0f, false, NONE, null);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, TesrMaterial.SpecialRender.GLINT, null, false);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, TesrMaterial.SpecialRender.GLINT, null);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, SHADER, false);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, true);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, SHADER);
assertNotEquals(base, other);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false);
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null);
assertEquals(base, other);
}
@Test
void nullTextureAndShaderHash() {
final TesrBatchRenderer.LayerKey key = new TesrBatchRenderer.LayerKey().set(null, null, false, false, false, false, 0f, false, null, null, false);
final TesrBatchRenderer.LayerKey key = new TesrBatchRenderer.LayerKey().set(null, null, false, false, false, false, 0f, false, null, null);
assertEquals(key, key.copy());
assertEquals(key.hashCode(), key.copy().hashCode());
}
@@ -0,0 +1,78 @@
package com.gtnewhorizons.angelica.rendering.tesr;
import com.gtnewhorizons.angelica.api.tesr.TesrMaterial;
import com.gtnewhorizons.angelica.compat.mojang.RenderLayer;
import com.gtnewhorizons.angelica.glsm.GLCoreTest;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.lwjgl.opengl.GL11;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@GLCoreTest
class TesrLayerStateTest {
@BeforeEach
void liveState() {
GLStateManager.disableFog();
GLStateManager.enableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.1f);
GLStateManager.enableDepthTest();
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glDepthMask(true);
GLStateManager.disableBlend();
GLStateManager.enableCull();
GLStateManager.enableLighting();
}
private static RenderLayer layer(TesrMaterial material) {
return RenderLayer.tesr(null, material);
}
@Test
void startDrawingLeavesUndeclaredPhasesToTheSurroundingContext() {
layer(TesrMaterial.CURRENT_STATE).startDrawing();
assertFalse(GLStateManager.getFogMode().isEnabled(), "fog");
}
@Test
void endDrawingLeavesUndeclaredPhasesToTheSurroundingContext() {
GLStateManager.enableFog();
final RenderLayer layer = layer(TesrMaterial.CURRENT_STATE);
layer.startDrawing();
layer.endDrawing();
assertTrue(GLStateManager.getFogMode().isEnabled(), "fog");
}
@Test
void declaredPhasesApply() {
layer(TesrMaterial.CURRENT_STATE).startDrawing();
assertFalse(GLStateManager.getAlphaTest().isEnabled(), "ZERO_ALPHA");
assertTrue(GLStateManager.getDepthTest().isEnabled(), "LEQUAL_DEPTH_TEST");
assertEquals(GL11.GL_LEQUAL, GLStateManager.getDepthState().getFunc());
assertFalse(GLStateManager.getBlendMode().isEnabled(), "NO_TRANSPARENCY");
assertEquals(GL11.GL_SMOOTH, GLStateManager.getShadeModelState().getValue(), "SMOOTH_SHADE_MODEL");
}
@Test
void everyMaterialToggleApplies() {
final TesrMaterial material = TesrMaterial.builder().noCull().unlit().noDepthWrite().cutout(0.5f).translucent().depthEqual().build();
layer(material).startDrawing();
assertFalse(GLStateManager.getCullState().isEnabled(), "noCull");
assertFalse(GLStateManager.getLightingState().isEnabled(), "unlit");
assertFalse(GLStateManager.getDepthState().isEnabled(), "noDepthWrite");
assertTrue(GLStateManager.getAlphaTest().isEnabled(), "cutout");
assertEquals(0.5f, GLStateManager.getAlphaState().getReference(), "cutout threshold");
assertTrue(GLStateManager.getBlendMode().isEnabled(), "translucent");
assertEquals(GL11.GL_SRC_ALPHA, GLStateManager.getBlendState().getSrcRgb());
assertEquals(GL11.GL_ONE_MINUS_SRC_ALPHA, GLStateManager.getBlendState().getDstRgb());
assertEquals(GL11.GL_EQUAL, GLStateManager.getDepthState().getFunc(), "depthEqual");
}
}