Fix Chisel energised voidstone missing its border corners (#2254)

Fixes #2246
This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-10-12 18:48:33 -07:00
1 parent 85d0641a73
commit 0cae2be1f6
4 files changed
+227 -37

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@ asmCompile = "5.0.3"
launchwrapper = "1.12"
# End Frozen
lwjgl3 = "3.4.2-SNAPSHOT"
lwjgl3 = "3.4.2"
# Must equal the LWJGL release shipped by lwjgl3ify. Do not bump without bumping lwjgl3ify.
lwjgl3Release = "3.4.2"
lwjgl3ify = "3.0.31"
@@ -36,7 +36,6 @@ import org.embeddedt.embeddium.impl.render.chunk.RenderPassConfiguration;
import org.embeddedt.embeddium.impl.render.chunk.compile.ChunkBuildBuffers;
import org.embeddedt.embeddium.impl.render.chunk.compile.ChunkBuildContext;
import org.embeddedt.embeddium.impl.render.chunk.data.MinecraftBuiltRenderSectionData;
import org.embeddedt.embeddium.impl.render.chunk.sprite.SpriteTransparencyLevel;
import org.embeddedt.embeddium.impl.render.chunk.terrain.material.Material;
import org.embeddedt.embeddium.impl.render.chunk.vertex.format.ChunkVertexEncoder;
import org.embeddedt.embeddium.impl.util.QuadUtil;
@@ -62,6 +61,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
@Getter private final FloatArrayList teBoundsScratch = new FloatArrayList();
@Getter private final long[] deferredMask = new long[64];
private final VertexArrayQuadView quadView;
private final QuadMaterialSelector materialSelector = new QuadMaterialSelector();
private final boolean hasColoredLight;
private final float[] tintResult = new float[3];
private List<IDynamicLightSource> chunkLightSources;
@@ -116,27 +116,6 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
}
}
private Material selectMaterial(Material material, TextureAtlasSprite sprite, boolean isShaderPackOverride,
boolean useRenderPassOptimization) {
// Don't apply transparency-based optimization when shader pack explicitly overrides the material
if (isShaderPackOverride) {
return material;
}
if (useRenderPassOptimization
&& sprite != null && sprite.getClass() == TextureAtlasSprite.class && !sprite.hasAnimationMetadata()) {
final var transparencyLevel = ((SpriteExtension) sprite).celeritas$getTransparencyLevel();
if (transparencyLevel == SpriteTransparencyLevel.OPAQUE
&& material == AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL) {
return AngelicaRenderPassConfiguration.SOLID_MATERIAL;
} else if (material == AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL && transparencyLevel != SpriteTransparencyLevel.TRANSLUCENT) {
return AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL;
}
}
return material;
}
@SuppressWarnings("unchecked")
public void copyRawBuffer(int[] rawBuffer, int vertexCount, int[] vertexStates,
int[] shaderOverrideBlockIds,
@@ -174,9 +153,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
final short originalBlockId = blockRenderContext.blockId;
int stateIdx = 0;
boolean hasCachedMaterial = false;
TextureAtlasSprite lastSprite = null;
Material lastMaterial = null;
materialSelector.reset(material, isShaderPackOverride, useRenderPassOptimization);
this.fluidQuadLightFace = null;
for (int quadIdx = 0; quadIdx < numQuads; quadIdx++) {
@@ -266,17 +243,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
// Apply RGB block light tint from provider
applyBlockLightTint(worldX, worldY, worldZ, vertices);
final Material correctMaterial;
if (material == AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL && hasVertexTransparency) {
correctMaterial = material;
} else if (hasCachedMaterial && sprite == lastSprite) {
correctMaterial = lastMaterial;
} else {
correctMaterial = selectMaterial(material, sprite, isShaderPackOverride, useRenderPassOptimization);
lastSprite = sprite;
lastMaterial = correctMaterial;
hasCachedMaterial = true;
}
final Material correctMaterial = materialSelector.select(facing, sprite, hasVertexTransparency);
final var builder = buffers.get(correctMaterial);
final int shaderOverrideBlockId = shaderOverrideBlockIds[quadIdx * 4];
@@ -0,0 +1,57 @@
package com.gtnewhorizons.angelica.rendering.celeritas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
import org.embeddedt.embeddium.impl.render.chunk.sprite.SpriteTransparencyLevel;
import org.embeddedt.embeddium.impl.render.chunk.terrain.material.Material;
class QuadMaterialSelector {
private Material material;
private boolean canDemote;
private int facesAtBaseMaterial;
private TextureAtlasSprite lastSprite;
private Material lastMaterial;
void reset(Material material, boolean isShaderPackOverride, boolean useRenderPassOptimization) {
this.material = material;
// Don't apply transparency-based optimization when shader pack explicitly overrides the material
this.canDemote = useRenderPassOptimization && !isShaderPackOverride;
facesAtBaseMaterial = 0;
lastMaterial = null;
}
Material select(ModelQuadFacing facing, TextureAtlasSprite sprite, boolean hasVertexTransparency) {
final int faceBit = 1 << facing.ordinal();
final Material correctMaterial;
if ((facesAtBaseMaterial & faceBit) != 0 || (material == AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL && hasVertexTransparency)) {
correctMaterial = material;
} else if (lastMaterial != null && sprite == lastSprite) {
correctMaterial = lastMaterial;
} else {
correctMaterial = demote(sprite);
lastSprite = sprite;
lastMaterial = correctMaterial;
}
if (correctMaterial == material) {
facesAtBaseMaterial |= faceBit;
}
return correctMaterial;
}
private Material demote(TextureAtlasSprite sprite) {
if (canDemote && sprite != null && sprite.getClass() == TextureAtlasSprite.class && !sprite.hasAnimationMetadata()) {
final var transparencyLevel = transparencyLevel(sprite);
if (transparencyLevel == SpriteTransparencyLevel.OPAQUE && material == AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL) {
return AngelicaRenderPassConfiguration.SOLID_MATERIAL;
} else if (material == AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL && transparencyLevel != SpriteTransparencyLevel.TRANSLUCENT) {
return AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL;
}
}
return material;
}
SpriteTransparencyLevel transparencyLevel(TextureAtlasSprite sprite) {
return ((SpriteExtension) sprite).celeritas$getTransparencyLevel();
}
}
@@ -0,0 +1,166 @@
package com.gtnewhorizons.angelica.rendering.celeritas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.data.AnimationMetadataSection;
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
import org.embeddedt.embeddium.impl.render.chunk.compile.sorting.QuadPrimitiveType;
import org.embeddedt.embeddium.impl.render.chunk.sprite.SpriteTransparencyLevel;
import org.embeddedt.embeddium.impl.render.chunk.terrain.TerrainRenderPass;
import org.embeddedt.embeddium.impl.render.chunk.terrain.material.Material;
import org.embeddedt.embeddium.impl.render.chunk.terrain.material.parameters.AlphaCutoffParameter;
import org.embeddedt.embeddium.impl.render.chunk.vertex.format.ChunkMeshFormats;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertSame;
class QuadMaterialSelectorTest {
private final Material[] previous = new Material[3];
private final Map<TextureAtlasSprite, SpriteTransparencyLevel> levels = new IdentityHashMap<>();
private final QuadMaterialSelector selector = new QuadMaterialSelector() {
@Override
SpriteTransparencyLevel transparencyLevel(TextureAtlasSprite sprite) {
return levels.get(sprite);
}
};
private Material solid;
private Material cutout;
private Material translucent;
@BeforeEach
void installMaterials() {
previous[0] = AngelicaRenderPassConfiguration.SOLID_MATERIAL;
previous[1] = AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL;
previous[2] = AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL;
solid = new Material(pass("solid", false), AlphaCutoffParameter.ZERO, true);
cutout = new Material(pass("cutout_mipped", true), AlphaCutoffParameter.HALF, true);
translucent = new Material(pass("translucent", false), AlphaCutoffParameter.ZERO, true);
AngelicaRenderPassConfiguration.SOLID_MATERIAL = solid;
AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL = cutout;
AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL = translucent;
}
@AfterEach
void restoreMaterials() {
AngelicaRenderPassConfiguration.SOLID_MATERIAL = previous[0];
AngelicaRenderPassConfiguration.CUTOUT_MIPPED_MATERIAL = previous[1];
AngelicaRenderPassConfiguration.TRANSLUCENT_MATERIAL = previous[2];
}
private static TerrainRenderPass pass(String name, boolean fragmentDiscard) {
return new TerrainRenderPass(name, null, false, fragmentDiscard, false, false, ChunkMeshFormats.VANILLA_LIKE, QuadPrimitiveType.TRIANGULATED, Map.of());
}
private TextureAtlasSprite sprite(String name, SpriteTransparencyLevel level) {
final TextureAtlasSprite sprite = new TextureAtlasSprite(name);
levels.put(sprite, level);
return sprite;
}
private TextureAtlasSprite animated(String name) {
final TextureAtlasSprite sprite = sprite(name, SpriteTransparencyLevel.OPAQUE);
sprite.animationMetadata = new AnimationMetadataSection(new ArrayList<>(), 16, 16, 1);
return sprite;
}
private TextureAtlasSprite custom(String name) {
final TextureAtlasSprite sprite = new TextureAtlasSprite(name) {};
levels.put(sprite, SpriteTransparencyLevel.OPAQUE);
return sprite;
}
private void begin(Material material) {
selector.reset(material, false, true);
}
private Material select(ModelQuadFacing facing, TextureAtlasSprite sprite) {
return selector.select(facing, sprite, false);
}
@Test
void opaqueOverlayStaysWithAnimatedBaseOnTheSameFace() {
final TextureAtlasSprite base = animated("hadesX32");
final TextureAtlasSprite corner = sprite("metalborder", SpriteTransparencyLevel.OPAQUE);
final TextureAtlasSprite edge = sprite("metalborder-ctm", SpriteTransparencyLevel.TRANSPARENT);
begin(cutout);
assertSame(cutout, select(ModelQuadFacing.POS_Z, base));
assertSame(cutout, select(ModelQuadFacing.POS_Z, corner));
assertSame(cutout, select(ModelQuadFacing.POS_Z, edge));
assertSame(cutout, select(ModelQuadFacing.POS_Z, corner));
}
@Test
void cachedDemotionDoesNotLeakOntoAFaceWithABase() {
final TextureAtlasSprite base = animated("hadesX32");
final TextureAtlasSprite corner = sprite("metalborder", SpriteTransparencyLevel.OPAQUE);
begin(cutout);
assertSame(solid, select(ModelQuadFacing.POS_X, corner));
assertSame(cutout, select(ModelQuadFacing.POS_Z, base));
assertSame(cutout, select(ModelQuadFacing.POS_Z, corner));
assertSame(solid, select(ModelQuadFacing.POS_X, corner));
}
@Test
void opaqueOnlyFacesAreStillDemoted() {
final TextureAtlasSprite stone = sprite("stone", SpriteTransparencyLevel.OPAQUE);
begin(cutout);
for (ModelQuadFacing facing : ModelQuadFacing.VALUES) {
assertSame(solid, select(facing, stone));
}
}
@Test
void vertexAlphaKeepsTranslucentAndPinsTheFace() {
final TextureAtlasSprite frame = sprite("frame", SpriteTransparencyLevel.TRANSPARENT);
begin(translucent);
assertSame(cutout, select(ModelQuadFacing.NEG_Y, frame));
assertSame(translucent, selector.select(ModelQuadFacing.POS_Y, frame, true));
assertSame(translucent, select(ModelQuadFacing.POS_Y, frame));
assertSame(cutout, select(ModelQuadFacing.NEG_Y, frame));
}
@Test
void undemotableSpritesKeepTheBaseMaterial() {
begin(cutout);
assertSame(cutout, select(ModelQuadFacing.POS_X, null));
assertSame(cutout, select(ModelQuadFacing.POS_Y, animated("animated")));
assertSame(cutout, select(ModelQuadFacing.POS_Z, custom("custom")));
}
@Test
void shaderPackOverrideAndDisabledOptimizationKeepTheBaseMaterial() {
final TextureAtlasSprite stone = sprite("stone", SpriteTransparencyLevel.OPAQUE);
selector.reset(cutout, true, true);
assertSame(cutout, select(ModelQuadFacing.POS_X, stone));
selector.reset(cutout, false, false);
assertSame(cutout, select(ModelQuadFacing.POS_X, stone));
}
@Test
void resetReleasesPinnedFacesAndTheSpriteCache() {
final TextureAtlasSprite base = animated("hadesX32");
final TextureAtlasSprite corner = sprite("metalborder", SpriteTransparencyLevel.OPAQUE);
begin(cutout);
assertSame(cutout, select(ModelQuadFacing.POS_Z, base));
assertSame(cutout, select(ModelQuadFacing.POS_Z, corner));
assertSame(solid, select(ModelQuadFacing.NEG_Z, corner));
begin(translucent);
assertSame(cutout, select(ModelQuadFacing.POS_Z, corner));
}
}