package net.minecraft.client.renderer.entity; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexMultiConsumer; import com.mojang.math.MatrixUtil; import java.util.List; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.Sheets; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.item.ItemModelResolver; import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ARGB; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class ItemRenderer { public static final ResourceLocation ENCHANTED_GLINT_ARMOR = ResourceLocation.withDefaultNamespace("textures/misc/enchanted_glint_armor.png"); public static final ResourceLocation ENCHANTED_GLINT_ITEM = ResourceLocation.withDefaultNamespace("textures/misc/enchanted_glint_item.png"); public static final int GUI_SLOT_CENTER_X = 8; public static final int GUI_SLOT_CENTER_Y = 8; public static final int ITEM_DECORATION_BLIT_OFFSET = 200; public static final float COMPASS_FOIL_UI_SCALE = 0.5F; public static final float COMPASS_FOIL_FIRST_PERSON_SCALE = 0.75F; public static final float COMPASS_FOIL_TEXTURE_SCALE = 0.0078125F; public static final int NO_TINT = -1; private final ItemModelResolver resolver; private final ItemStackRenderState scratchItemStackRenderState = new ItemStackRenderState(); public ItemRenderer(ItemModelResolver resolver) { this.resolver = resolver; } public static void renderItem( ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, int[] tintLayers, List quads, RenderType renderType, ItemStackRenderState.FoilType foilType ) { VertexConsumer vertexConsumer; if (foilType == ItemStackRenderState.FoilType.SPECIAL) { PoseStack.Pose pose = poseStack.last().copy(); if (displayContext == ItemDisplayContext.GUI) { MatrixUtil.mulComponentWise(pose.pose(), 0.5F); } else if (displayContext.firstPerson()) { MatrixUtil.mulComponentWise(pose.pose(), 0.75F); } vertexConsumer = getCompassFoilBuffer(bufferSource, renderType, pose); } else { vertexConsumer = getFoilBuffer(bufferSource, renderType, true, foilType != ItemStackRenderState.FoilType.NONE); } renderQuadList(poseStack, vertexConsumer, quads, tintLayers, packedLight, packedOverlay); } public static VertexConsumer getArmorFoilBuffer(MultiBufferSource bufferSource, RenderType renderType, boolean hasFoil) { return hasFoil ? VertexMultiConsumer.create(bufferSource.getBuffer(RenderType.armorEntityGlint()), bufferSource.getBuffer(renderType)) : bufferSource.getBuffer(renderType); } private static VertexConsumer getCompassFoilBuffer(MultiBufferSource bufferSource, RenderType renderType, PoseStack.Pose pose) { return VertexMultiConsumer.create( new SheetedDecalTextureGenerator(bufferSource.getBuffer(RenderType.glint()), pose, 0.0078125F), bufferSource.getBuffer(renderType) ); } public static VertexConsumer getFoilBuffer(MultiBufferSource bufferSource, RenderType renderType, boolean isItem, boolean glint) { if (glint) { return Minecraft.useShaderTransparency() && renderType == Sheets.translucentItemSheet() ? VertexMultiConsumer.create(bufferSource.getBuffer(RenderType.glintTranslucent()), bufferSource.getBuffer(renderType)) : VertexMultiConsumer.create(bufferSource.getBuffer(isItem ? RenderType.glint() : RenderType.entityGlint()), bufferSource.getBuffer(renderType)); } else { return bufferSource.getBuffer(renderType); } } private static int getLayerColorSafe(int[] tintLayers, int index) { return index >= 0 && index < tintLayers.length ? tintLayers[index] : -1; } private static void renderQuadList(PoseStack poseStack, VertexConsumer buffer, List quads, int[] tintLayers, int packedLight, int packedOverlay) { PoseStack.Pose pose = poseStack.last(); for (BakedQuad bakedQuad : quads) { float f; float g; float h; float j; if (bakedQuad.isTinted()) { int i = getLayerColorSafe(tintLayers, bakedQuad.tintIndex()); f = ARGB.alpha(i) / 255.0F; g = ARGB.red(i) / 255.0F; h = ARGB.green(i) / 255.0F; j = ARGB.blue(i) / 255.0F; } else { f = 1.0F; g = 1.0F; h = 1.0F; j = 1.0F; } buffer.putBulkData(pose, bakedQuad, g, h, j, f, packedLight, packedOverlay); } } public void renderStatic( ItemStack stack, ItemDisplayContext displayContext, int packedLight, int packedOverlay, PoseStack poseStack, MultiBufferSource bufferSource, @Nullable Level level, int seed ) { this.renderStatic(null, stack, displayContext, poseStack, bufferSource, level, packedLight, packedOverlay, seed); } public void renderStatic( @Nullable LivingEntity entity, ItemStack stack, ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource bufferSource, @Nullable Level level, int packedLight, int packedOverlay, int seed ) { this.resolver.updateForTopItem(this.scratchItemStackRenderState, stack, displayContext, level, entity, seed); this.scratchItemStackRenderState.render(poseStack, bufferSource, packedLight, packedOverlay); } }