Skip to content

Instantly share code, notes, and snippets.

@lowercasebtw
Last active April 18, 2025 22:29
Show Gist options
  • Select an option

  • Save lowercasebtw/50884139e0def281d75db5f71a976082 to your computer and use it in GitHub Desktop.

Select an option

Save lowercasebtw/50884139e0def281d75db5f71a976082 to your computer and use it in GitHub Desktop.
MixinItemRenderer
import com.mojang.blaze3d.buffers.BufferType;
import com.mojang.blaze3d.buffers.BufferUsage;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
import com.mojang.blaze3d.vertex.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.world.item.ItemDisplayContext;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.function.Consumer;
@Mixin(ItemRenderer.class)
public abstract class MixinItemRenderer {
@Shadow
private static void renderQuadList(
PoseStack poseStack,
VertexConsumer vertexConsumer,
List<BakedQuad> list,
int[] tints,
int light,
int color
) {
}
@Inject(method = "renderItem", at = @At("HEAD"), cancellable = true)
private static void usePipelines(
ItemDisplayContext itemDisplayContext,
PoseStack poseStack,
MultiBufferSource multiBufferSource,
int light,
int color,
int[] tints,
List<BakedQuad> bakedQuads,
RenderType renderType,
ItemStackRenderState.FoilType foilType,
CallbackInfo ci
) {
if (TheItemRenderPipelineMod.ENABLED) {
ci.cancel();
// Note: Looked into using VertexMultiConsumer but couldn't as I couldn't get MeshData from it
// as it was not a BufferBuilder. Also, the vertex formats between ITEM_ENTITY_TRANSLUCENT_CULL and GLINT are different,
// so it'd prob cause issues.
Consumer<VertexConsumer> renderQuadConsumer = (vertexConsumer) -> renderQuadList(poseStack, vertexConsumer, bakedQuads, tints, light, color);
RenderTarget renderTarget = renderType.getRenderTarget();
renderItemLayer(RenderPipelines.ITEM_ENTITY_TRANSLUCENT_CULL, renderTarget, false, renderQuadConsumer);
if (foilType != ItemStackRenderState.FoilType.NONE) {
RenderStateShardAccessor.setupGlintTexturingMatrix(8.0F);
renderItemLayer(RenderPipelines.GLINT, renderTarget, true, renderQuadConsumer);
RenderSystem.resetTextureMatrix();
}
}
}
// Ideally, to be like the more recent code, we'd need to know how many vertex's there are
// and create a ByteBufferBuilder with the default format mode times the vertex count
// instead of using Tesselator which I assume will soon be removed/phased out.
// I.E: Example from SkyRenderer#init
@Unique
private static void renderItemLayer(RenderPipeline renderPipeline, RenderTarget renderTarget, boolean glint, Consumer<VertexConsumer> vertexConsumerConsumer) {
BufferBuilder builder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, renderPipeline.getVertexFormat());
vertexConsumerConsumer.accept(builder);
GpuBuffer buffer;
int indexCount;
try (MeshData meshData = builder.buildOrThrow()) {
indexCount = meshData.drawState().indexCount();
buffer = RenderSystem.getDevice().createBuffer(() -> "Item Rendering", BufferType.VERTICES, BufferUsage.DYNAMIC_WRITE, meshData.vertexBuffer());
}
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
GpuTexture texture = Minecraft.getInstance().getTextureManager().getTexture(glint ? ItemRenderer.ENCHANTED_GLINT_ITEM : TextureAtlas.LOCATION_BLOCKS).getTexture();
RenderSystem.AutoStorageIndexBuffer indexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
try (RenderPass renderPass = RenderSystem.getDevice()
.createCommandEncoder()
.createRenderPass(renderTarget.getColorTexture(), OptionalInt.empty(), renderTarget.getDepthTexture(), OptionalDouble.empty())) {
renderPass.setPipeline(renderPipeline);
renderPass.setVertexBuffer(0, buffer);
renderPass.setIndexBuffer(indexBuffer.getBuffer(indexCount), indexBuffer.type());
renderPass.bindSampler("Sampler0", texture);
if (!glint) {
renderPass.bindSampler("Sampler1", ((OverlayTextureAccessor) gameRenderer.overlayTexture()).getDynamicTexture().getTexture());
renderPass.bindSampler("Sampler2", gameRenderer.lightTexture().getTarget());
}
renderPass.drawIndexed(0, indexCount);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment