274 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.entity;
 | |
| 
 | |
| import com.mojang.blaze3d.vertex.PoseStack;
 | |
| import com.mojang.blaze3d.vertex.VertexConsumer;
 | |
| import com.mojang.math.Axis;
 | |
| import com.mojang.math.Transformation;
 | |
| import java.util.ArrayList;
 | |
| import java.util.List;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.Camera;
 | |
| import net.minecraft.client.Minecraft;
 | |
| import net.minecraft.client.gui.Font;
 | |
| import net.minecraft.client.renderer.LightTexture;
 | |
| import net.minecraft.client.renderer.MultiBufferSource;
 | |
| import net.minecraft.client.renderer.RenderType;
 | |
| import net.minecraft.client.renderer.block.BlockRenderDispatcher;
 | |
| import net.minecraft.client.renderer.entity.state.BlockDisplayEntityRenderState;
 | |
| import net.minecraft.client.renderer.entity.state.DisplayEntityRenderState;
 | |
| import net.minecraft.client.renderer.entity.state.ItemDisplayEntityRenderState;
 | |
| import net.minecraft.client.renderer.entity.state.TextDisplayEntityRenderState;
 | |
| import net.minecraft.client.renderer.item.ItemModelResolver;
 | |
| import net.minecraft.client.renderer.texture.OverlayTexture;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.network.chat.Component;
 | |
| import net.minecraft.util.FormattedCharSequence;
 | |
| import net.minecraft.world.entity.Display;
 | |
| import net.minecraft.world.phys.AABB;
 | |
| import org.joml.Matrix4f;
 | |
| import org.joml.Quaternionf;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public abstract class DisplayRenderer<T extends Display, S, ST extends DisplayEntityRenderState> extends EntityRenderer<T, ST> {
 | |
| 	private final EntityRenderDispatcher entityRenderDispatcher;
 | |
| 
 | |
| 	protected DisplayRenderer(EntityRendererProvider.Context context) {
 | |
| 		super(context);
 | |
| 		this.entityRenderDispatcher = context.getEntityRenderDispatcher();
 | |
| 	}
 | |
| 
 | |
| 	protected AABB getBoundingBoxForCulling(T minecraft) {
 | |
| 		return minecraft.getBoundingBoxForCulling();
 | |
| 	}
 | |
| 
 | |
| 	protected boolean affectedByCulling(T display) {
 | |
| 		return display.affectedByCulling();
 | |
| 	}
 | |
| 
 | |
| 	private static int getBrightnessOverride(Display display) {
 | |
| 		Display.RenderState renderState = display.renderState();
 | |
| 		return renderState != null ? renderState.brightnessOverride() : -1;
 | |
| 	}
 | |
| 
 | |
| 	protected int getSkyLightLevel(T entity, BlockPos pos) {
 | |
| 		int i = getBrightnessOverride(entity);
 | |
| 		return i != -1 ? LightTexture.sky(i) : super.getSkyLightLevel(entity, pos);
 | |
| 	}
 | |
| 
 | |
| 	protected int getBlockLightLevel(T entity, BlockPos pos) {
 | |
| 		int i = getBrightnessOverride(entity);
 | |
| 		return i != -1 ? LightTexture.block(i) : super.getBlockLightLevel(entity, pos);
 | |
| 	}
 | |
| 
 | |
| 	protected float getShadowRadius(ST renderState) {
 | |
| 		Display.RenderState renderState2 = renderState.renderState;
 | |
| 		return renderState2 == null ? 0.0F : renderState2.shadowRadius().get(renderState.interpolationProgress);
 | |
| 	}
 | |
| 
 | |
| 	protected float getShadowStrength(ST renderState) {
 | |
| 		Display.RenderState renderState2 = renderState.renderState;
 | |
| 		return renderState2 == null ? 0.0F : renderState2.shadowStrength().get(renderState.interpolationProgress);
 | |
| 	}
 | |
| 
 | |
| 	public void render(ST renderState, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
 | |
| 		Display.RenderState renderState2 = renderState.renderState;
 | |
| 		if (renderState2 != null && renderState.hasSubState()) {
 | |
| 			float f = renderState.interpolationProgress;
 | |
| 			super.render(renderState, poseStack, bufferSource, packedLight);
 | |
| 			poseStack.pushPose();
 | |
| 			poseStack.mulPose(this.calculateOrientation(renderState2, renderState, new Quaternionf()));
 | |
| 			Transformation transformation = renderState2.transformation().get(f);
 | |
| 			poseStack.mulPose(transformation.getMatrix());
 | |
| 			this.renderInner(renderState, poseStack, bufferSource, packedLight, f);
 | |
| 			poseStack.popPose();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Quaternionf calculateOrientation(Display.RenderState renderState, ST entityRenderState, Quaternionf quaternion) {
 | |
| 		Camera camera = this.entityRenderDispatcher.camera;
 | |
| 
 | |
| 		return switch (renderState.billboardConstraints()) {
 | |
| 			case FIXED -> quaternion.rotationYXZ(
 | |
| 				(float) (-Math.PI / 180.0) * entityRenderState.entityYRot, (float) (Math.PI / 180.0) * entityRenderState.entityXRot, 0.0F
 | |
| 			);
 | |
| 			case HORIZONTAL -> quaternion.rotationYXZ((float) (-Math.PI / 180.0) * entityRenderState.entityYRot, (float) (Math.PI / 180.0) * cameraXRot(camera), 0.0F);
 | |
| 			case VERTICAL -> quaternion.rotationYXZ((float) (-Math.PI / 180.0) * cameraYrot(camera), (float) (Math.PI / 180.0) * entityRenderState.entityXRot, 0.0F);
 | |
| 			case CENTER -> quaternion.rotationYXZ((float) (-Math.PI / 180.0) * cameraYrot(camera), (float) (Math.PI / 180.0) * cameraXRot(camera), 0.0F);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private static float cameraYrot(Camera camera) {
 | |
| 		return camera.getYRot() - 180.0F;
 | |
| 	}
 | |
| 
 | |
| 	private static float cameraXRot(Camera camera) {
 | |
| 		return -camera.getXRot();
 | |
| 	}
 | |
| 
 | |
| 	private static <T extends Display> float entityYRot(T entity, float partialTick) {
 | |
| 		return entity.getYRot(partialTick);
 | |
| 	}
 | |
| 
 | |
| 	private static <T extends Display> float entityXRot(T entity, float partialTick) {
 | |
| 		return entity.getXRot(partialTick);
 | |
| 	}
 | |
| 
 | |
| 	protected abstract void renderInner(ST renderState, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, float interpolationProgress);
 | |
| 
 | |
| 	public void extractRenderState(T entity, ST reusedState, float partialTick) {
 | |
| 		super.extractRenderState(entity, reusedState, partialTick);
 | |
| 		reusedState.renderState = entity.renderState();
 | |
| 		reusedState.interpolationProgress = entity.calculateInterpolationProgress(partialTick);
 | |
| 		reusedState.entityYRot = entityYRot(entity, partialTick);
 | |
| 		reusedState.entityXRot = entityXRot(entity, partialTick);
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public static class BlockDisplayRenderer extends DisplayRenderer<Display.BlockDisplay, Display.BlockDisplay.BlockRenderState, BlockDisplayEntityRenderState> {
 | |
| 		private final BlockRenderDispatcher blockRenderer;
 | |
| 
 | |
| 		protected BlockDisplayRenderer(EntityRendererProvider.Context context) {
 | |
| 			super(context);
 | |
| 			this.blockRenderer = context.getBlockRenderDispatcher();
 | |
| 		}
 | |
| 
 | |
| 		public BlockDisplayEntityRenderState createRenderState() {
 | |
| 			return new BlockDisplayEntityRenderState();
 | |
| 		}
 | |
| 
 | |
| 		public void extractRenderState(Display.BlockDisplay blockDisplay, BlockDisplayEntityRenderState blockDisplayEntityRenderState, float f) {
 | |
| 			super.extractRenderState(blockDisplay, blockDisplayEntityRenderState, f);
 | |
| 			blockDisplayEntityRenderState.blockRenderState = blockDisplay.blockRenderState();
 | |
| 		}
 | |
| 
 | |
| 		public void renderInner(BlockDisplayEntityRenderState blockDisplayEntityRenderState, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, float f) {
 | |
| 			this.blockRenderer
 | |
| 				.renderSingleBlock(blockDisplayEntityRenderState.blockRenderState.blockState(), poseStack, multiBufferSource, i, OverlayTexture.NO_OVERLAY);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public static class ItemDisplayRenderer extends DisplayRenderer<Display.ItemDisplay, Display.ItemDisplay.ItemRenderState, ItemDisplayEntityRenderState> {
 | |
| 		private final ItemModelResolver itemModelResolver;
 | |
| 
 | |
| 		protected ItemDisplayRenderer(EntityRendererProvider.Context context) {
 | |
| 			super(context);
 | |
| 			this.itemModelResolver = context.getItemModelResolver();
 | |
| 		}
 | |
| 
 | |
| 		public ItemDisplayEntityRenderState createRenderState() {
 | |
| 			return new ItemDisplayEntityRenderState();
 | |
| 		}
 | |
| 
 | |
| 		public void extractRenderState(Display.ItemDisplay itemDisplay, ItemDisplayEntityRenderState itemDisplayEntityRenderState, float f) {
 | |
| 			super.extractRenderState(itemDisplay, itemDisplayEntityRenderState, f);
 | |
| 			Display.ItemDisplay.ItemRenderState itemRenderState = itemDisplay.itemRenderState();
 | |
| 			if (itemRenderState != null) {
 | |
| 				this.itemModelResolver.updateForNonLiving(itemDisplayEntityRenderState.item, itemRenderState.itemStack(), itemRenderState.itemTransform(), itemDisplay);
 | |
| 			} else {
 | |
| 				itemDisplayEntityRenderState.item.clear();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public void renderInner(ItemDisplayEntityRenderState itemDisplayEntityRenderState, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, float f) {
 | |
| 			if (!itemDisplayEntityRenderState.item.isEmpty()) {
 | |
| 				poseStack.mulPose(Axis.YP.rotation((float) Math.PI));
 | |
| 				itemDisplayEntityRenderState.item.render(poseStack, multiBufferSource, i, OverlayTexture.NO_OVERLAY);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public static class TextDisplayRenderer extends DisplayRenderer<Display.TextDisplay, Display.TextDisplay.TextRenderState, TextDisplayEntityRenderState> {
 | |
| 		private final Font font;
 | |
| 
 | |
| 		protected TextDisplayRenderer(EntityRendererProvider.Context context) {
 | |
| 			super(context);
 | |
| 			this.font = context.getFont();
 | |
| 		}
 | |
| 
 | |
| 		public TextDisplayEntityRenderState createRenderState() {
 | |
| 			return new TextDisplayEntityRenderState();
 | |
| 		}
 | |
| 
 | |
| 		public void extractRenderState(Display.TextDisplay entity, TextDisplayEntityRenderState reusedState, float partialTick) {
 | |
| 			super.extractRenderState(entity, reusedState, partialTick);
 | |
| 			reusedState.textRenderState = entity.textRenderState();
 | |
| 			reusedState.cachedInfo = entity.cacheDisplay(this::splitLines);
 | |
| 		}
 | |
| 
 | |
| 		private Display.TextDisplay.CachedInfo splitLines(Component text, int maxWidth) {
 | |
| 			List<FormattedCharSequence> list = this.font.split(text, maxWidth);
 | |
| 			List<Display.TextDisplay.CachedLine> list2 = new ArrayList(list.size());
 | |
| 			int i = 0;
 | |
| 
 | |
| 			for (FormattedCharSequence formattedCharSequence : list) {
 | |
| 				int j = this.font.width(formattedCharSequence);
 | |
| 				i = Math.max(i, j);
 | |
| 				list2.add(new Display.TextDisplay.CachedLine(formattedCharSequence, j));
 | |
| 			}
 | |
| 
 | |
| 			return new Display.TextDisplay.CachedInfo(list2, i);
 | |
| 		}
 | |
| 
 | |
| 		public void renderInner(
 | |
| 			TextDisplayEntityRenderState renderState, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, float interpolationProgress
 | |
| 		) {
 | |
| 			Display.TextDisplay.TextRenderState textRenderState = renderState.textRenderState;
 | |
| 			byte b = textRenderState.flags();
 | |
| 			boolean bl = (b & 2) != 0;
 | |
| 			boolean bl2 = (b & 4) != 0;
 | |
| 			boolean bl3 = (b & 1) != 0;
 | |
| 			Display.TextDisplay.Align align = Display.TextDisplay.getAlign(b);
 | |
| 			byte c = (byte)textRenderState.textOpacity().get(interpolationProgress);
 | |
| 			int i;
 | |
| 			if (bl2) {
 | |
| 				float f = Minecraft.getInstance().options.getBackgroundOpacity(0.25F);
 | |
| 				i = (int)(f * 255.0F) << 24;
 | |
| 			} else {
 | |
| 				i = textRenderState.backgroundColor().get(interpolationProgress);
 | |
| 			}
 | |
| 
 | |
| 			float f = 0.0F;
 | |
| 			Matrix4f matrix4f = poseStack.last().pose();
 | |
| 			matrix4f.rotate((float) Math.PI, 0.0F, 1.0F, 0.0F);
 | |
| 			matrix4f.scale(-0.025F, -0.025F, -0.025F);
 | |
| 			Display.TextDisplay.CachedInfo cachedInfo = renderState.cachedInfo;
 | |
| 			int j = 1;
 | |
| 			int k = 9 + 1;
 | |
| 			int l = cachedInfo.width();
 | |
| 			int m = cachedInfo.lines().size() * k - 1;
 | |
| 			matrix4f.translate(1.0F - l / 2.0F, -m, 0.0F);
 | |
| 			if (i != 0) {
 | |
| 				VertexConsumer vertexConsumer = bufferSource.getBuffer(bl ? RenderType.textBackgroundSeeThrough() : RenderType.textBackground());
 | |
| 				vertexConsumer.addVertex(matrix4f, -1.0F, -1.0F, 0.0F).setColor(i).setLight(packedLight);
 | |
| 				vertexConsumer.addVertex(matrix4f, -1.0F, (float)m, 0.0F).setColor(i).setLight(packedLight);
 | |
| 				vertexConsumer.addVertex(matrix4f, (float)l, (float)m, 0.0F).setColor(i).setLight(packedLight);
 | |
| 				vertexConsumer.addVertex(matrix4f, (float)l, -1.0F, 0.0F).setColor(i).setLight(packedLight);
 | |
| 			}
 | |
| 
 | |
| 			for (Display.TextDisplay.CachedLine cachedLine : cachedInfo.lines()) {
 | |
| 				float g = switch (align) {
 | |
| 					case LEFT -> 0.0F;
 | |
| 					case RIGHT -> l - cachedLine.width();
 | |
| 					case CENTER -> l / 2.0F - cachedLine.width() / 2.0F;
 | |
| 				};
 | |
| 				this.font
 | |
| 					.drawInBatch(
 | |
| 						cachedLine.contents(),
 | |
| 						g,
 | |
| 						f,
 | |
| 						c << 24 | 16777215,
 | |
| 						bl3,
 | |
| 						matrix4f,
 | |
| 						bufferSource,
 | |
| 						bl ? Font.DisplayMode.SEE_THROUGH : Font.DisplayMode.POLYGON_OFFSET,
 | |
| 						0,
 | |
| 						packedLight
 | |
| 					);
 | |
| 				f += k;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |