aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
diff options
context:
space:
mode:
authorAnthony Hilyard <anthony.hilyard@gmail.com>2022-12-22 15:20:04 -0800
committerAnthony Hilyard <anthony.hilyard@gmail.com>2022-12-22 15:20:04 -0800
commitce46c0feb25b6127a1ce4e5624a05acf5ce16a71 (patch)
treedf65f661c8dc001838d15979a5316fe5db0935eb /src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
parent379e47c13645498bc9fe3c810bef4bba5994504b (diff)
downloadIceberg-ce46c0feb25b6127a1ce4e5624a05acf5ce16a71.tar.gz
Iceberg-ce46c0feb25b6127a1ce4e5624a05acf5ce16a71.tar.bz2
Iceberg-ce46c0feb25b6127a1ce4e5624a05acf5ce16a71.zip
Added new selectors and item rendering capability.
- Added wildcard item selector. - Added selector negation. - Added selector combination. - Item detail models can now be rendered via the custom item renderer. - Fixed several tooltip rendering bugs. - Added Minecraft 1.19.3 support.
Diffstat (limited to 'src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java')
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java617
1 files changed, 594 insertions, 23 deletions
diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
index b77bb09..301b4c4 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
@@ -1,50 +1,115 @@
package com.anthonyhilyard.iceberg.renderer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import com.google.common.collect.Maps;
+
+import org.joml.Matrix4f;
+import org.joml.Quaternionf;
+import org.joml.Vector3f;
+
+import org.lwjgl.opengl.GL11;
+
import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.mojang.datafixers.util.Pair;
+import com.mojang.math.MatrixUtil;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.pipeline.MainTarget;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.platform.Lighting;
+import com.mojang.blaze3d.platform.GlStateManager.SourceFactor;
+import com.mojang.blaze3d.platform.GlStateManager.DestFactor;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.lwjgl.opengl.GL11;
-
+import net.minecraft.CrashReport;
+import net.minecraft.CrashReportCategory;
+import net.minecraft.ReportedException;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.texture.TextureManager;
-
-import com.mojang.blaze3d.platform.GlStateManager.SourceFactor;
-import com.mojang.blaze3d.platform.GlStateManager.DestFactor;
-import com.mojang.math.Matrix4f;
-
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
+import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.MultiBufferSource.BufferSource;
import net.minecraft.client.renderer.block.model.ItemTransforms;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.tags.ItemTags;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.EquipmentSlot;
+import net.minecraft.world.entity.animal.horse.Horse;
+import net.minecraft.world.entity.decoration.ArmorStand;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.entity.vehicle.AbstractMinecart;
+import net.minecraft.world.entity.vehicle.Boat;
+import net.minecraft.world.entity.vehicle.ChestBoat;
import net.minecraft.world.inventory.InventoryMenu;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.BoatItem;
+import net.minecraft.world.item.HorseArmorItem;
+import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
+import net.minecraft.world.item.MinecartItem;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.EntityBlock;
+import net.minecraft.world.level.block.HalfTransparentBlock;
+import net.minecraft.world.level.block.StainedGlassPaneBlock;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.properties.BlockStateProperties;
+import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
+
+import net.minecraftforge.client.ForgeHooksClient;
+import net.minecraftforge.client.extensions.common.IClientItemExtensions;
/**
- * An extended ItemRenderer that allows items to be rendered to RenderTarget before drawing to screen.
- * This allows alpha values to be supported properly by all item types, even semi-transparent items.
+ * An extended ItemRenderer with extended functionality, such as allowing items to be rendered to a RenderTarget
+ * before drawing to screen for alpha support, and allowing handheld item models to be rendered into the gui.
*/
public class CustomItemRenderer extends ItemRenderer
{
- @SuppressWarnings("unused")
- private static final Logger LOGGER = LogManager.getLogger();
+ /* Cylindrical bounds for a model. */
+ private record ModelBounds(Vector3f center, float height, float radius) {}
private static RenderTarget iconFrameBuffer = null;
+ private static ArmorStand armorStand = null;
+ private static AbstractMinecart minecart = null;
+ private static Boat boat = null;
+ private static Horse horse = null;
+ private static Pair<Item, CompoundTag> cachedArmorStandItem = null;
+ private static Pair<Item, CompoundTag> cachedHorseArmorItem = null;
+ private static Map<Item, ModelBounds> modelBoundsCache = Maps.newHashMap();
+
+ private static final List<Direction> quadDirections;
+ static {
+ quadDirections = new ArrayList<>(Arrays.asList(Direction.values()));
+ quadDirections.add(null);
+ }
+
private Minecraft mc;
-
+ private final ModelManager modelManager;
+ private final BlockEntityWithoutLevelRenderer blockEntityRenderer;
+
public CustomItemRenderer(TextureManager textureManagerIn, ModelManager modelManagerIn, ItemColors itemColorsIn, BlockEntityWithoutLevelRenderer blockEntityRendererIn, Minecraft mcIn)
{
super(textureManagerIn, modelManagerIn, itemColorsIn, blockEntityRendererIn);
mc = mcIn;
+ modelManager = modelManagerIn;
+ blockEntityRenderer = blockEntityRendererIn;
// Initialize the icon framebuffer if needed.
if (iconFrameBuffer == null)
@@ -56,6 +121,509 @@ public class CustomItemRenderer extends ItemRenderer
}
}
+ private void renderGuiModel(ItemStack itemStack, int x, int y, Quaternionf rotation, BakedModel bakedModel)
+ {
+ mc.getTextureManager().getTexture(InventoryMenu.BLOCK_ATLAS).setFilter(false, false);
+ RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
+ RenderSystem.enableBlend();
+ RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
+ RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+ PoseStack modelViewStack = RenderSystem.getModelViewStack();
+ modelViewStack.pushPose();
+ modelViewStack.translate(x, y, 100.0f + blitOffset);
+
+ modelViewStack.translate(8.0f, 8.0f, 0.0f);
+ modelViewStack.scale(1.0f, -1.0f, 1.0f);
+ modelViewStack.scale(16.0f, 16.0f, 16.0f);
+ RenderSystem.applyModelViewMatrix();
+
+ BufferSource bufferSource = Minecraft.getInstance().renderBuffers().bufferSource();
+ boolean flatLighting = !bakedModel.usesBlockLight();
+ if (flatLighting) { Lighting.setupForFlatItems(); }
+
+ PoseStack poseStack = new PoseStack();
+ renderModel(itemStack, ItemTransforms.TransformType.GUI, false, poseStack, rotation, bufferSource, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, bakedModel);
+
+ poseStack.popPose();
+ bufferSource.endBatch();
+ RenderSystem.enableDepthTest();
+ if (flatLighting) { Lighting.setupFor3DItems(); }
+
+ modelViewStack.popPose();
+ RenderSystem.applyModelViewMatrix();
+ }
+
+ @SuppressWarnings("deprecation")
+ private void renderEntityModel(Entity entity, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ EntityRenderDispatcher entityRenderDispatcher = minecraft.getEntityRenderDispatcher();
+ Lighting.setupForEntityInInventory();
+ RenderSystem.enableDepthTest();
+ RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
+ entityRenderDispatcher.setRenderShadow(false);
+
+ RenderSystem.runAsFancy(() -> entityRenderDispatcher.render(entity, 0.0, 0.0, 0.0, 0.0f, 1.0f, poseStack, bufferSource, packedLight));
+
+ if (bufferSource instanceof BufferSource)
+ {
+ ((BufferSource)bufferSource).endBatch();
+ }
+
+ entityRenderDispatcher.setRenderShadow(true);
+
+ RenderSystem.applyModelViewMatrix();
+ Lighting.setupFor3DItems();
+ }
+
+ private <T extends MultiBufferSource> void renderModelInternal(ItemStack itemStack, ItemTransforms.TransformType transformType, boolean leftHanded, PoseStack poseStack,
+ Quaternionf rotation, T bufferSource, int packedLight, int packedOverlay, BakedModel bakedModel,
+ Predicate<T> bufferSourceReady)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+
+ if (Player.getEquipmentSlotForItem(itemStack).isArmor())
+ {
+ if (updateArmorStand(itemStack))
+ {
+ renderEntityModel(armorStand, poseStack, bufferSource, packedLight);
+ }
+ }
+
+ if (!bakedModel.isCustomRenderer() && !itemStack.is(Items.TRIDENT))
+ {
+ boolean fabulous;
+ if (transformType != ItemTransforms.TransformType.GUI && !transformType.firstPerson() && itemStack.getItem() instanceof BlockItem)
+ {
+ Block block = ((BlockItem)itemStack.getItem()).getBlock();
+ fabulous = !(block instanceof HalfTransparentBlock) && !(block instanceof StainedGlassPaneBlock);
+ }
+ else
+ {
+ fabulous = true;
+ }
+
+ if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof BlockItem blockItem)
+ {
+ BakedModel blockModel = null;
+ boolean isBlockEntity = false;
+
+ blockModel = minecraft.getBlockRenderer().getBlockModelShaper().getBlockModel(blockItem.getBlock().defaultBlockState());
+ if (blockModel != modelManager.getMissingModel())
+ {
+ // First try rendering via the BlockEntityWithoutLevelRenderer.
+ blockEntityRenderer.renderByItem(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay);
+ }
+ else
+ {
+ blockModel = null;
+ }
+
+ if (blockItem.getBlock().defaultBlockState().hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF))
+ {
+ // This is a double block, so we'll need to render both halves.
+ // First render the bottom half.
+ BlockState bottomState = blockItem.getBlock().defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER);
+ BakedModel bottomModel = minecraft.getBlockRenderer().getBlockModelShaper().getBlockModel(bottomState);
+ renderBakedModel(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay, bottomModel, fabulous);
+
+ // Then render the top half.
+ poseStack.pushPose();
+ poseStack.translate(0.0f, 1.0f, 0.0f);
+ BlockState topState = blockItem.getBlock().defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER);
+ BakedModel topModel = minecraft.getBlockRenderer().getBlockModelShaper().getBlockModel(topState);
+ renderBakedModel(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay, topModel, fabulous);
+ poseStack.popPose();
+ }
+
+ if (blockItem.getBlock() instanceof EntityBlock entityBlock)
+ {
+ isBlockEntity = true;
+ try
+ {
+ renderBlockEntity(itemStack, poseStack, bufferSource, packedLight, packedOverlay, minecraft, entityBlock, blockItem.getBlock().defaultBlockState());
+ }
+ catch (Exception e)
+ {
+ // This can fail for things like beacons that require a level. We'll just ignore it.
+ }
+ }
+
+ // If we still haven't rendered anything or this is a block entity, try rendering the block model.
+ if (blockModel != null && (bufferSourceReady.test(bufferSource) || isBlockEntity))
+ {
+ renderBakedModel(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay, blockModel, fabulous);
+ }
+ }
+
+ // Now try rendering entity models for items that spawn minecarts or boats.
+ if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof MinecartItem minecartItem)
+ {
+ if (updateMinecart(minecartItem))
+ {
+ renderEntityModel(minecart, poseStack, bufferSource, packedLight);
+ }
+ }
+
+ if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof BoatItem boatItem)
+ {
+ if (updateBoat(boatItem))
+ {
+ renderEntityModel(boat, poseStack, bufferSource, packedLight);
+ }
+ }
+
+ // If this is horse armor, render it here.
+ if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof HorseArmorItem)
+ {
+ if (updateHorse(itemStack))
+ {
+ renderEntityModel(horse, poseStack, bufferSource, packedLight);
+ }
+ }
+
+ // Finally, fall back to just rendering the item model.
+ if (bufferSourceReady.test(bufferSource))
+ {
+ renderBakedModel(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay, bakedModel, fabulous);
+ }
+ }
+ else if (bufferSourceReady.test(bufferSource))
+ {
+ IClientItemExtensions.of(itemStack).getCustomRenderer().renderByItem(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay);
+ }
+ }
+
+ private void renderModel(ItemStack itemStack, ItemTransforms.TransformType transformType, boolean leftHanded, PoseStack poseStack, Quaternionf rotation, MultiBufferSource bufferSource, int packedLight, int packedOverlay, BakedModel bakedModel)
+ {
+ if (!itemStack.isEmpty())
+ {
+ boolean isBlockItem = false, spawnsEntity = false, isArmor = false;
+ if (itemStack.getItem() instanceof BlockItem blockItem)
+ {
+ isBlockItem = true;
+ }
+ else if (itemStack.getItem() instanceof MinecartItem || itemStack.getItem() instanceof BoatItem)
+ {
+ spawnsEntity = true;
+ }
+
+ if (Player.getEquipmentSlotForItem(itemStack).isArmor())
+ {
+ isArmor = true;
+ }
+
+ poseStack.pushPose();
+
+ if (isBlockItem || spawnsEntity)
+ {
+ // Apply the standard block rotation so block entities match other blocks.
+ poseStack.mulPose(new Quaternionf().rotationXYZ((float)Math.toRadians(30.0f), (float)Math.toRadians(225.0f), 0.0f));
+ }
+ else
+ {
+ ForgeHooksClient.handleCameraTransforms(poseStack, bakedModel, transformType, leftHanded);
+ }
+
+ // Get the model bounds.
+ ModelBounds modelBounds = getModelBounds(itemStack, transformType, leftHanded, poseStack, rotation, bufferSource, packedLight, packedOverlay, bakedModel);
+
+ // Undo the camera transforms now that we have the model bounds.
+ poseStack.popPose();
+ poseStack.pushPose();
+
+ // Rotate the model.
+ poseStack.mulPose(rotation);
+
+ // Scale the model to fit.
+ float scale = 1.0f / Math.max(modelBounds.height, modelBounds.radius * 2.0f);
+ scale *= isBlockItem ? 0.8f : 1.0f;
+
+ // Adjust the scale based on the armor type.
+ if (isArmor)
+ {
+ switch (Player.getEquipmentSlotForItem(itemStack))
+ {
+ case HEAD:
+ scale *= 0.75f;
+ break;
+ case LEGS:
+ scale *= 1.1f;
+ break;
+ default:
+ break;
+ }
+ }
+ poseStack.scale(scale, scale, scale);
+
+ // Translate the model to the center of the item.
+ poseStack.translate(-modelBounds.center.x(), -modelBounds.center.y(), -modelBounds.center.z());
+
+ // Reapply the camera transforms.
+ if (isBlockItem || spawnsEntity)
+ {
+ // Apply the standard block rotation so block entities match other blocks.
+ poseStack.mulPose(new Quaternionf().rotationXYZ((float)Math.toRadians(30.0f), (float)Math.toRadians(225.0f), 0.0f));
+ }
+ else
+ {
+ bakedModel = ForgeHooksClient.handleCameraTransforms(poseStack, bakedModel, transformType, leftHanded);
+ }
+
+ CheckedBufferSource checkedBufferSource = new CheckedBufferSource(bufferSource);
+ renderModelInternal(itemStack, transformType, leftHanded, poseStack, rotation, checkedBufferSource, packedLight, packedOverlay, bakedModel, b -> !b.hasRendered());
+
+ poseStack.popPose();
+ }
+ }
+
+ private void renderBlockEntity(ItemStack itemStack, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight,
+ int packedOverlay, Minecraft minecraft, EntityBlock entityBlock, BlockState blockState) throws Exception
+ {
+ // If we didn't render via the BlockEntityWithoutLevelRenderer, now check if this is a block entity and render that.
+ BlockEntity blockEntity = entityBlock.newBlockEntity(BlockPos.ZERO, blockState);
+ if (blockEntity != null)
+ {
+ if (itemStack.getTag() != null)
+ {
+ blockEntity.load(itemStack.getTag());
+ }
+
+ BlockEntityRenderer<BlockEntity> renderer = minecraft.getBlockEntityRenderDispatcher().getRenderer(blockEntity);
+ if (renderer != null)
+ {
+ renderer.render(blockEntity, minecraft.getFrameTime(), poseStack, bufferSource, packedLight, packedOverlay);
+ }
+ }
+ }
+
+ private void renderBakedModel(ItemStack itemStack, ItemTransforms.TransformType transformType, PoseStack poseStack,
+ MultiBufferSource bufferSource, int packedLight, int packedOverlay, BakedModel bakedModel, boolean fabulous)
+ {
+ for (var model : bakedModel.getRenderPasses(itemStack, fabulous))
+ {
+ for (var rendertype : model.getRenderTypes(itemStack, fabulous))
+ {
+ VertexConsumer vertexconsumer;
+ if (itemStack.is(ItemTags.COMPASSES) && itemStack.hasFoil())
+ {
+ poseStack.pushPose();
+ PoseStack.Pose posestack$pose = poseStack.last();
+ if (transformType == ItemTransforms.TransformType.GUI)
+ {
+ MatrixUtil.mulComponentWise(posestack$pose.pose(), 0.5F);
+ }
+ else if (transformType.firstPerson())
+ {
+ MatrixUtil.mulComponentWise(posestack$pose.pose(), 0.75F);
+ }
+
+ if (fabulous)
+ {
+ vertexconsumer = getCompassFoilBufferDirect(bufferSource, rendertype, posestack$pose);
+ }
+ else
+ {
+ vertexconsumer = getCompassFoilBuffer(bufferSource, rendertype, posestack$pose);
+ }
+
+ poseStack.popPose();
+ }
+ else if (fabulous)
+ {
+ vertexconsumer = getFoilBufferDirect(bufferSource, rendertype, true, itemStack.hasFoil());
+ }
+ else
+ {
+ vertexconsumer = getFoilBuffer(bufferSource, rendertype, true, itemStack.hasFoil());
+ }
+
+ renderModelLists(model, itemStack, packedLight, packedOverlay, poseStack, vertexconsumer);
+ }
+ }
+ }
+
+ private boolean updateArmorStand(ItemStack itemStack)
+ {
+ EquipmentSlot equipmentSlot = Player.getEquipmentSlotForItem(itemStack);
+ if (!equipmentSlot.isArmor())
+ {
+ // This isn't armor, so don't render anything.
+ return false;
+ }
+
+ if (armorStand == null)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ armorStand = EntityType.ARMOR_STAND.create(minecraft.level);
+ armorStand.setInvisible(true);
+ }
+
+ // If somehow the armor stand is still null, then we can't render anything.
+ if (armorStand == null)
+ {
+ return false;
+ }
+
+ // If the item has changed, then we need to update the armor stand.
+ if (cachedArmorStandItem != Pair.of(itemStack.getItem(), itemStack.getTag()))
+ {
+ // Clear the armor stand.
+ for (EquipmentSlot slot : EquipmentSlot.values())
+ {
+ armorStand.setItemSlot(slot, ItemStack.EMPTY);
+ }
+
+ // Equip the armor stand with the armor.
+ armorStand.setItemSlot(equipmentSlot, itemStack);
+
+ cachedArmorStandItem = Pair.of(itemStack.getItem(), itemStack.getTag());
+ }
+ return true;
+ }
+
+ private boolean updateMinecart(MinecartItem item)
+ {
+ if (minecart == null || minecart.getMinecartType() != item.type)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ minecart = AbstractMinecart.createMinecart(minecraft.level, 0, 0, 0, item.type);
+ }
+
+ // If somehow the minecart is still null, then we can't render anything.
+ return minecart != null;
+ }
+
+ private boolean updateBoat(BoatItem item)
+ {
+ if (boat == null || boat.getVariant() != item.type || (boat instanceof ChestBoat) != item.hasChest)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ boat = item.hasChest ? new ChestBoat(minecraft.level, 0, 0, 0) : new Boat(minecraft.level, 0, 0, 0);
+ boat.setVariant(item.type);
+ }
+
+ // If somehow the boat is still null, then we can't render anything.
+ return boat != null;
+ }
+
+ private boolean updateHorse(ItemStack horseArmorItem)
+ {
+ // If this isn't a horse armor item, we can't render anything.
+ if (!(horseArmorItem.getItem() instanceof HorseArmorItem))
+ {
+ return false;
+ }
+
+ if (horse == null)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ horse = EntityType.HORSE.create(minecraft.level);
+ horse.setInvisible(true);
+ horse.canUpdate(false);
+ }
+
+ // If somehow the horse is still null, then we can't render anything.
+ if (horse == null)
+ {
+ return false;
+ }
+
+ // If the item has changed, then we need to update the horse.
+ if (cachedHorseArmorItem != Pair.of(horseArmorItem.getItem(), horseArmorItem.getTag()))
+ {
+ // Equip the horse with the armor.
+ horse.setItemSlot(EquipmentSlot.CHEST, horseArmorItem);
+
+ cachedHorseArmorItem = Pair.of(horseArmorItem.getItem(), horseArmorItem.getTag());
+ }
+ return true;
+ }
+
+ private ModelBounds boundsFromVertices(List<Vector3f> vertices)
+ {
+ Vector3f center = new Vector3f();
+ float radius = 0.0F;
+ float height = 0.0F;
+
+ float minX = Float.MAX_VALUE;
+ float minY = Float.MAX_VALUE;
+ float minZ = Float.MAX_VALUE;
+ float maxX = Float.MIN_VALUE;
+ float maxY = Float.MIN_VALUE;
+ float maxZ = Float.MIN_VALUE;
+
+ for (Vector3f vertex : vertices)
+ {
+ minX = Math.min(minX, vertex.x);
+ minY = Math.min(minY, vertex.y);
+ minZ = Math.min(minZ, vertex.z);
+ maxX = Math.max(maxX, vertex.x);
+ maxY = Math.max(maxY, vertex.y);
+ maxZ = Math.max(maxZ, vertex.z);
+ }
+
+ center = new Vector3f((minX + maxX) / 2.0F, (minY + maxY) / 2.0F, (minZ + maxZ) / 2.0F);
+ height = maxY - minY;
+
+ for (Vector3f vertex : vertices)
+ {
+ radius = Math.max(radius, (float) Math.sqrt((vertex.x - center.x) * (vertex.x - center.x) + (vertex.y - center.y) * (vertex.y - center.y)));
+ }
+
+ return new ModelBounds(center, height, radius);
+ }
+
+ private ModelBounds getModelBounds(ItemStack itemStack, ItemTransforms.TransformType transformType, boolean leftHanded, PoseStack poseStack,
+ Quaternionf rotation, MultiBufferSource bufferSource, int packedLight, int packedOverlay, BakedModel bakedModel)
+ {
+ if (!modelBoundsCache.containsKey(itemStack.getItem()))
+ {
+ VertexCollector vertexCollector = new VertexCollector();
+ renderModelInternal(itemStack, transformType, leftHanded, poseStack, rotation, vertexCollector, packedLight, packedOverlay, bakedModel, b -> b.getVertices().isEmpty());
+
+ // Now store the bounds in the cache.
+ modelBoundsCache.put(itemStack.getItem(), boundsFromVertices(vertexCollector.getVertices()));
+ }
+
+ return modelBoundsCache.get(itemStack.getItem());
+ }
+
+ public void renderDetailModelIntoGUI(ItemStack stack, int x, int y, Quaternionf rotation)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ BakedModel bakedModel = minecraft.getItemRenderer().getModel(stack, minecraft.level, minecraft.player, 0);
+
+ blitOffset += 50.0f;
+
+ try
+ {
+ renderGuiModel(stack, x, y, rotation, bakedModel);
+ }
+ catch (Throwable throwable)
+ {
+ CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering item");
+ CrashReportCategory crashreportcategory = crashreport.addCategory("Item being rendered");
+ crashreportcategory.setDetail("Item Type", () -> {
+ return String.valueOf((Object)stack.getItem());
+ });
+ crashreportcategory.setDetail("Registry Name", () -> String.valueOf(net.minecraftforge.registries.ForgeRegistries.ITEMS.getKey(stack.getItem())));
+ crashreportcategory.setDetail("Item Damage", () -> {
+ return String.valueOf(stack.getDamageValue());
+ });
+ crashreportcategory.setDetail("Item NBT", () -> {
+ return String.valueOf((Object)stack.getTag());
+ });
+ crashreportcategory.setDetail("Item Foil", () -> {
+ return String.valueOf(stack.hasFoil());
+ });
+ throw new ReportedException(crashreport);
+ }
+
+ blitOffset -= 50.0f;
+ }
+
public void renderItemModelIntoGUIWithAlpha(ItemStack stack, int x, int y, float alpha)
{
BakedModel bakedModel = mc.getItemRenderer().getModel(stack, null, null, 0);
@@ -65,9 +633,12 @@ public class CustomItemRenderer extends ItemRenderer
iconFrameBuffer.clear(Minecraft.ON_OSX);
iconFrameBuffer.bindWrite(true);
+ Matrix4f matrix = new Matrix4f();
+ matrix.setOrtho(0.0f, iconFrameBuffer.width, iconFrameBuffer.height, 0.0f, 1000.0f, 3000.0f);
+
RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, Minecraft.ON_OSX);
RenderSystem.backupProjectionMatrix();
- RenderSystem.setProjectionMatrix(Matrix4f.orthographic(0.0f, iconFrameBuffer.width, iconFrameBuffer.height, 0.0f, 1000.0f, 3000.0f));
+ RenderSystem.setProjectionMatrix(matrix);
Lighting.setupFor3DItems();
@@ -75,23 +646,23 @@ public class CustomItemRenderer extends ItemRenderer
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
- RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
+ RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
PoseStack modelViewStack = RenderSystem.getModelViewStack();
modelViewStack.pushPose();
modelViewStack.setIdentity();
modelViewStack.translate(48.0f, 48.0f, -2000.0f);
- modelViewStack.scale(96.0F, 96.0F, 96.0F);
+ modelViewStack.scale(96.0f, 96.0f, 96.0f);
RenderSystem.applyModelViewMatrix();
PoseStack poseStack = new PoseStack();
- MultiBufferSource.BufferSource multibuffersource$buffersource = Minecraft.getInstance().renderBuffers().bufferSource();
- boolean flag = !bakedModel.usesBlockLight();
- if (flag) { Lighting.setupForFlatItems(); }
+ BufferSource bufferSource = Minecraft.getInstance().renderBuffers().bufferSource();
+ boolean flatLighting = !bakedModel.usesBlockLight();
+ if (flatLighting) { Lighting.setupForFlatItems(); }
- render(stack, ItemTransforms.TransformType.GUI, false, poseStack, multibuffersource$buffersource, 0xF000F0, OverlayTexture.NO_OVERLAY, bakedModel);
- multibuffersource$buffersource.endBatch();
+ render(stack, ItemTransforms.TransformType.GUI, false, poseStack, bufferSource, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, bakedModel);
+ bufferSource.endBatch();
RenderSystem.enableDepthTest();
- if (flag) { Lighting.setupFor3DItems(); }
+ if (flatLighting) { Lighting.setupFor3DItems(); }
modelViewStack.popPose();
RenderSystem.applyModelViewMatrix();