Fix incorrect JEI block rendering for Infested Leaves and Crucible Heat Source categories

This commit is contained in:
thedarkcolour 2026-05-15 12:37:37 -07:00
parent 65dd68fe6b
commit 7a01d94f37

View File

@ -1,35 +1,45 @@
package thedarkcolour.exdeorum.compat;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.TextureSetup;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.client.renderer.block.BlockAndTintGetter;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.state.gui.GuiElementRenderState;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import org.joml.Matrix3x2f;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.RenderUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
// client-only logic shared between JEI and EMI
public class ClientXeiUtil {
private static final ItemStack OAK_BARREL_COMPOSTING = new ItemStack(DefaultMaterials.OAK_BARREL.getItemHolder(), 1, DataComponentPatch.builder().set(DataComponents.ITEM_MODEL, ExDeorum.loc("oak_barrel_composting")).build());
public static void renderBlock(GuiGraphicsExtractor guiGraphics, BlockState state, float x, float y, float z, float scale) {
var fluidState = state.getFluidState();
if (!fluidState.isEmpty()) {
var sprite = RenderUtil.getFluidSprite(fluidState.getType());
guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, Math.round(x), Math.round(y), Math.round(scale), Math.round(scale));
return;
}
var stack = new ItemStack(state.getBlock());
if (!stack.isEmpty()) {
renderScaledItem(guiGraphics, stack, x, y, scale);
}
submitBlockPreview(guiGraphics, state, x, y, z, scale);
}
public static void renderItemWithAsterisk(GuiGraphicsExtractor graphics, ItemStack stack) {
@ -53,12 +63,189 @@ public class ClientXeiUtil {
return Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY);
}
private static void renderScaledItem(GuiGraphicsExtractor graphics, ItemStack stack, float x, float y, float scale) {
var pose = graphics.pose();
pose.pushMatrix();
pose.translate(x, y);
pose.scale(scale / 16f);
graphics.fakeItem(stack, 0, 0);
pose.popMatrix();
private static void submitBlockPreview(GuiGraphicsExtractor graphics, BlockState state, float x, float y, float z, float scale) {
graphics.submitGuiElementRenderState(new BlockPreviewRenderState(new Matrix3x2f(graphics.pose()), state, x, y, z, scale));
}
private record BlockPreviewRenderState(Matrix3x2f pose, BlockState state, float x, float y, float z,
float scale) implements GuiElementRenderState {
private static final ScreenRectangle NO_SCISSOR = null;
@Override
public void buildVertices(VertexConsumer consumer) {
var matrix = createBlockPreviewMatrix(x, y, z, scale);
var quads = new ArrayList<PreviewQuad>();
var fluidState = state.getFluidState();
if (fluidState.isEmpty()) {
var model = Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(state);
var parts = new ArrayList<BlockStateModelPart>();
model.collectParts(BlockAndTintGetter.EMPTY, BlockPos.ZERO, state, RandomSource.create(42), parts);
for (var part : parts) {
for (var direction : net.minecraft.core.Direction.values()) {
for (var quad : part.getQuads(direction)) {
quads.add(PreviewQuad.fromBakedQuad(quad, matrix, getBlockTint(state, quad)));
}
}
for (var quad : part.getQuads(null)) {
quads.add(PreviewQuad.fromBakedQuad(quad, matrix, getBlockTint(state, quad)));
}
}
} else {
addFluidCube(quads, matrix, fluidState.getType());
}
quads.sort(Comparator.comparingDouble(PreviewQuad::depth));
for (var quad : quads) {
quad.emit(consumer, pose);
}
}
@Override
public RenderPipeline pipeline() {
return RenderPipelines.GUI_TEXTURED;
}
@Override
public TextureSetup textureSetup() {
AbstractTexture texture = Minecraft.getInstance().getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS);
return TextureSetup.singleTexture(texture.getTextureView(), texture.getSampler());
}
@Override
public ScreenRectangle scissorArea() {
return NO_SCISSOR;
}
@Override
public ScreenRectangle bounds() {
int minX = (int) Math.floor(x - scale);
int minY = (int) Math.floor(y - scale);
int size = (int) Math.ceil(scale * 2.0f);
return new ScreenRectangle(minX, minY, size, size).transformAxisAligned(pose);
}
}
private record PreviewQuad(ProjectedVertex v0, ProjectedVertex v1, ProjectedVertex v2, ProjectedVertex v3,
float depth) {
private static PreviewQuad fromBakedQuad(net.minecraft.client.resources.model.geometry.BakedQuad quad, Matrix4f matrix, int color) {
var v0 = ProjectedVertex.fromBakedQuad(quad.position(0), quad.packedUV(0), matrix, color);
var v1 = ProjectedVertex.fromBakedQuad(quad.position(1), quad.packedUV(1), matrix, color);
var v2 = ProjectedVertex.fromBakedQuad(quad.position(2), quad.packedUV(2), matrix, color);
var v3 = ProjectedVertex.fromBakedQuad(quad.position(3), quad.packedUV(3), matrix, color);
float centerX = matrix.transformPosition(0.5f, 0.5f, 0.5f, new Vector3f()).x;
float quadX = (v0.x + v1.x + v2.x + v3.x) * 0.25f;
float shade = quad.materialInfo().shade() ? getGuiFaceShade(quad.direction(), quadX, centerX) : 1.0f;
return new PreviewQuad(
v0.withColor(shadeColor(v0.color, shade)),
v1.withColor(shadeColor(v1.color, shade)),
v2.withColor(shadeColor(v2.color, shade)),
v3.withColor(shadeColor(v3.color, shade)),
(v0.z + v1.z + v2.z + v3.z) * 0.25f
);
}
private static PreviewQuad fromSprite(Vector3fc p0, Vector3fc p1, Vector3fc p2, Vector3fc p3, Matrix4f matrix, TextureAtlasSprite sprite, int color) {
var v0 = ProjectedVertex.fromSprite(p0, matrix, sprite.getU0(), sprite.getV0(), color);
var v1 = ProjectedVertex.fromSprite(p1, matrix, sprite.getU0(), sprite.getV1(), color);
var v2 = ProjectedVertex.fromSprite(p2, matrix, sprite.getU1(), sprite.getV1(), color);
var v3 = ProjectedVertex.fromSprite(p3, matrix, sprite.getU1(), sprite.getV0(), color);
return new PreviewQuad(v0, v1, v2, v3, (v0.z + v1.z + v2.z + v3.z) * 0.25f);
}
private void emit(VertexConsumer consumer, Matrix3x2f pose) {
v0.emit(consumer, pose);
v1.emit(consumer, pose);
v2.emit(consumer, pose);
v3.emit(consumer, pose);
}
}
private record ProjectedVertex(float x, float y, float z, float u, float v, int color) {
private static ProjectedVertex fromBakedQuad(Vector3fc position, long packedUv, Matrix4f matrix, int color) {
var transformed = matrix.transformPosition(position, new Vector3f());
float u = Float.intBitsToFloat((int) (packedUv >> 32));
float v = Float.intBitsToFloat((int) packedUv);
return new ProjectedVertex(transformed.x, transformed.y, transformed.z, u, v, color);
}
private static ProjectedVertex fromSprite(Vector3fc position, Matrix4f matrix, float u, float v, int color) {
var transformed = matrix.transformPosition(position, new Vector3f());
return new ProjectedVertex(transformed.x, transformed.y, transformed.z, u, v, color);
}
private void emit(VertexConsumer consumer, Matrix3x2f pose) {
consumer.addVertexWith2DPose(pose, x, y).setUv(u, v).setColor(color);
}
private ProjectedVertex withColor(int color) {
return new ProjectedVertex(x, y, z, u, v, color);
}
}
private static Matrix4f createBlockPreviewMatrix(float x, float y, float z, float scale) {
return new Matrix4f()
.translate(x, y, z)
.scale(-scale, -scale, -scale)
.translate(-0.5f, -0.5f, 0.0f)
.rotateX((float) Math.toRadians(-30.0f))
.translate(0.5f, 0.0f, -0.5f)
.rotateY((float) Math.toRadians(45.0f))
.translate(-0.5f, 0.0f, 0.5f)
.translate(0.0f, 0.0f, -1.0f);
}
private static void addFluidCube(List<PreviewQuad> quads, Matrix4f matrix, net.minecraft.world.level.material.Fluid fluid) {
var still = RenderUtil.getFluidSprite(fluid);
int color = 0xffffffff;
var level = Minecraft.getInstance().level;
if (level != null) {
color = 0xff000000 | (RenderUtil.getFluidColor(fluid, level, net.minecraft.core.BlockPos.ZERO) & 0xffffff);
}
var p000 = new Vector3f(0.0f, 0.0f, 0.0f);
var p001 = new Vector3f(0.0f, 0.0f, 1.0f);
var p010 = new Vector3f(0.0f, 1.0f, 0.0f);
var p011 = new Vector3f(0.0f, 1.0f, 1.0f);
var p100 = new Vector3f(1.0f, 0.0f, 0.0f);
var p101 = new Vector3f(1.0f, 0.0f, 1.0f);
var p110 = new Vector3f(1.0f, 1.0f, 0.0f);
var p111 = new Vector3f(1.0f, 1.0f, 1.0f);
quads.add(PreviewQuad.fromSprite(p010, p011, p111, p110, matrix, still, color));
quads.add(PreviewQuad.fromSprite(p000, p100, p101, p001, matrix, still, color));
quads.add(PreviewQuad.fromSprite(p001, p101, p111, p011, matrix, still, color));
quads.add(PreviewQuad.fromSprite(p100, p000, p010, p110, matrix, still, color));
quads.add(PreviewQuad.fromSprite(p000, p001, p011, p010, matrix, still, color));
quads.add(PreviewQuad.fromSprite(p101, p100, p110, p111, matrix, still, color));
}
private static int getBlockTint(BlockState state, net.minecraft.client.resources.model.geometry.BakedQuad quad) {
var material = quad.materialInfo();
if (!material.isTinted()) {
return -1;
}
var tintSource = Minecraft.getInstance().getBlockColors().getTintSource(state, material.tintIndex());
if (tintSource == null) {
return -1;
}
return 0xff000000 | (tintSource.color(state) & 0xffffff);
}
private static float getGuiFaceShade(net.minecraft.core.Direction direction, float quadX, float centerX) {
return switch (direction) {
case UP -> 1.0f;
case DOWN -> 0.5f;
default -> quadX < centerX ? 0.8f : 0.6f;
};
}
private static int shadeColor(int color, float shade) {
int alpha = color & 0xff000000;
int red = Math.min(255, Math.round(((color >> 16) & 0xff) * shade));
int green = Math.min(255, Math.round(((color >> 8) & 0xff) * shade));
int blue = Math.min(255, Math.round((color & 0xff) * shade));
return alpha | red << 16 | green << 8 | blue;
}
}