272 lines
12 KiB
Java
272 lines
12 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.gui.Font.DisplayMode;
|
|
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.EntityRendererProvider.Context;
|
|
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.entity.Display.BlockDisplay.BlockRenderState;
|
|
import net.minecraft.world.entity.Display.ItemDisplay.ItemRenderState;
|
|
import net.minecraft.world.entity.Display.TextDisplay.Align;
|
|
import net.minecraft.world.entity.Display.TextDisplay.CachedInfo;
|
|
import net.minecraft.world.entity.Display.TextDisplay.CachedLine;
|
|
import net.minecraft.world.entity.Display.TextDisplay.TextRenderState;
|
|
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(Context context) {
|
|
super(context);
|
|
this.entityRenderDispatcher = context.getEntityRenderDispatcher();
|
|
}
|
|
|
|
protected AABB getBoundingBoxForCulling(T display) {
|
|
return display.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 display, BlockPos blockPos) {
|
|
int i = getBrightnessOverride(display);
|
|
return i != -1 ? LightTexture.sky(i) : super.getSkyLightLevel(display, blockPos);
|
|
}
|
|
|
|
protected int getBlockLightLevel(T display, BlockPos blockPos) {
|
|
int i = getBrightnessOverride(display);
|
|
return i != -1 ? LightTexture.block(i) : super.getBlockLightLevel(display, blockPos);
|
|
}
|
|
|
|
protected float getShadowRadius(ST displayEntityRenderState) {
|
|
Display.RenderState renderState = displayEntityRenderState.renderState;
|
|
return renderState == null ? 0.0F : renderState.shadowRadius().get(displayEntityRenderState.interpolationProgress);
|
|
}
|
|
|
|
protected float getShadowStrength(ST displayEntityRenderState) {
|
|
Display.RenderState renderState = displayEntityRenderState.renderState;
|
|
return renderState == null ? 0.0F : renderState.shadowStrength().get(displayEntityRenderState.interpolationProgress);
|
|
}
|
|
|
|
public void render(ST displayEntityRenderState, PoseStack poseStack, MultiBufferSource multiBufferSource, int i) {
|
|
Display.RenderState renderState = displayEntityRenderState.renderState;
|
|
if (renderState != null && displayEntityRenderState.hasSubState()) {
|
|
float f = displayEntityRenderState.interpolationProgress;
|
|
super.render(displayEntityRenderState, poseStack, multiBufferSource, i);
|
|
poseStack.pushPose();
|
|
poseStack.mulPose(this.calculateOrientation(renderState, displayEntityRenderState, new Quaternionf()));
|
|
Transformation transformation = renderState.transformation().get(f);
|
|
poseStack.mulPose(transformation.getMatrix());
|
|
this.renderInner(displayEntityRenderState, poseStack, multiBufferSource, i, 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 display, ST displayEntityRenderState, float f) {
|
|
super.extractRenderState(display, displayEntityRenderState, f);
|
|
displayEntityRenderState.renderState = display.renderState();
|
|
displayEntityRenderState.interpolationProgress = display.calculateInterpolationProgress(f);
|
|
displayEntityRenderState.entityYRot = entityYRot(display, f);
|
|
displayEntityRenderState.entityXRot = entityXRot(display, f);
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public static class BlockDisplayRenderer extends DisplayRenderer<Display.BlockDisplay, BlockRenderState, BlockDisplayEntityRenderState> {
|
|
private final BlockRenderDispatcher blockRenderer;
|
|
|
|
protected BlockDisplayRenderer(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, ItemRenderState, ItemDisplayEntityRenderState> {
|
|
private final ItemModelResolver itemModelResolver;
|
|
|
|
protected ItemDisplayRenderer(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);
|
|
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, TextRenderState, TextDisplayEntityRenderState> {
|
|
private final Font font;
|
|
|
|
protected TextDisplayRenderer(Context context) {
|
|
super(context);
|
|
this.font = context.getFont();
|
|
}
|
|
|
|
public TextDisplayEntityRenderState createRenderState() {
|
|
return new TextDisplayEntityRenderState();
|
|
}
|
|
|
|
public void extractRenderState(Display.TextDisplay textDisplay, TextDisplayEntityRenderState textDisplayEntityRenderState, float f) {
|
|
super.extractRenderState(textDisplay, textDisplayEntityRenderState, f);
|
|
textDisplayEntityRenderState.textRenderState = textDisplay.textRenderState();
|
|
textDisplayEntityRenderState.cachedInfo = textDisplay.cacheDisplay(this::splitLines);
|
|
}
|
|
|
|
private CachedInfo splitLines(Component text, int maxWidth) {
|
|
List<FormattedCharSequence> list = this.font.split(text, maxWidth);
|
|
List<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 CachedLine(formattedCharSequence, j));
|
|
}
|
|
|
|
return new CachedInfo(list2, i);
|
|
}
|
|
|
|
public void renderInner(TextDisplayEntityRenderState textDisplayEntityRenderState, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, float f) {
|
|
TextRenderState textRenderState = textDisplayEntityRenderState.textRenderState;
|
|
byte b = textRenderState.flags();
|
|
boolean bl = (b & 2) != 0;
|
|
boolean bl2 = (b & 4) != 0;
|
|
boolean bl3 = (b & 1) != 0;
|
|
Align align = Display.TextDisplay.getAlign(b);
|
|
byte c = (byte)textRenderState.textOpacity().get(f);
|
|
int j;
|
|
if (bl2) {
|
|
float g = Minecraft.getInstance().options.getBackgroundOpacity(0.25F);
|
|
j = (int)(g * 255.0F) << 24;
|
|
} else {
|
|
j = textRenderState.backgroundColor().get(f);
|
|
}
|
|
|
|
float g = 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);
|
|
CachedInfo cachedInfo = textDisplayEntityRenderState.cachedInfo;
|
|
int k = 1;
|
|
int l = 9 + 1;
|
|
int m = cachedInfo.width();
|
|
int n = cachedInfo.lines().size() * l - 1;
|
|
matrix4f.translate(1.0F - m / 2.0F, -n, 0.0F);
|
|
if (j != 0) {
|
|
VertexConsumer vertexConsumer = multiBufferSource.getBuffer(bl ? RenderType.textBackgroundSeeThrough() : RenderType.textBackground());
|
|
vertexConsumer.addVertex(matrix4f, -1.0F, -1.0F, 0.0F).setColor(j).setLight(i);
|
|
vertexConsumer.addVertex(matrix4f, -1.0F, (float)n, 0.0F).setColor(j).setLight(i);
|
|
vertexConsumer.addVertex(matrix4f, (float)m, (float)n, 0.0F).setColor(j).setLight(i);
|
|
vertexConsumer.addVertex(matrix4f, (float)m, -1.0F, 0.0F).setColor(j).setLight(i);
|
|
}
|
|
|
|
for (CachedLine cachedLine : cachedInfo.lines()) {
|
|
float h = switch (align) {
|
|
case LEFT -> 0.0F;
|
|
case RIGHT -> m - cachedLine.width();
|
|
case CENTER -> m / 2.0F - cachedLine.width() / 2.0F;
|
|
default -> throw new MatchException(null, null);
|
|
};
|
|
this.font
|
|
.drawInBatch(
|
|
cachedLine.contents(), h, g, c << 24 | 16777215, bl3, matrix4f, multiBufferSource, bl ? DisplayMode.SEE_THROUGH : DisplayMode.POLYGON_OFFSET, 0, i
|
|
);
|
|
g += l;
|
|
}
|
|
}
|
|
}
|
|
}
|