package net.minecraft.client.renderer.entity; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.state.PaintingRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.PaintingTextureManager; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; import net.minecraft.world.entity.decoration.Painting; import net.minecraft.world.entity.decoration.PaintingVariant; import net.minecraft.world.level.Level; @Environment(EnvType.CLIENT) public class PaintingRenderer extends EntityRenderer { public PaintingRenderer(EntityRendererProvider.Context context) { super(context); } public void render(PaintingRenderState renderState, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) { PaintingVariant paintingVariant = renderState.variant; if (paintingVariant != null) { poseStack.pushPose(); poseStack.mulPose(Axis.YP.rotationDegrees(180 - renderState.direction.get2DDataValue() * 90)); PaintingTextureManager paintingTextureManager = Minecraft.getInstance().getPaintingTextures(); TextureAtlasSprite textureAtlasSprite = paintingTextureManager.getBackSprite(); VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.entitySolidZOffsetForward(textureAtlasSprite.atlasLocation())); this.renderPainting( poseStack, vertexConsumer, renderState.lightCoords, paintingVariant.width(), paintingVariant.height(), paintingTextureManager.get(paintingVariant), textureAtlasSprite ); poseStack.popPose(); super.render(renderState, poseStack, bufferSource, packedLight); } } public PaintingRenderState createRenderState() { return new PaintingRenderState(); } public void extractRenderState(Painting entity, PaintingRenderState reusedState, float partialTick) { super.extractRenderState(entity, reusedState, partialTick); Direction direction = entity.getDirection(); PaintingVariant paintingVariant = entity.getVariant().value(); reusedState.direction = direction; reusedState.variant = paintingVariant; int i = paintingVariant.width(); int j = paintingVariant.height(); if (reusedState.lightCoords.length != i * j) { reusedState.lightCoords = new int[i * j]; } float f = -i / 2.0F; float g = -j / 2.0F; Level level = entity.level(); for (int k = 0; k < j; k++) { for (int l = 0; l < i; l++) { float h = l + f + 0.5F; float m = k + g + 0.5F; int n = entity.getBlockX(); int o = Mth.floor(entity.getY() + m); int p = entity.getBlockZ(); switch (direction) { case NORTH: n = Mth.floor(entity.getX() + h); break; case WEST: p = Mth.floor(entity.getZ() - h); break; case SOUTH: n = Mth.floor(entity.getX() - h); break; case EAST: p = Mth.floor(entity.getZ() + h); } reusedState.lightCoords[l + k * i] = LevelRenderer.getLightColor(level, new BlockPos(n, o, p)); } } } private void renderPainting( PoseStack poseStack, VertexConsumer buffer, int[] lightCoords, int width, int height, TextureAtlasSprite frontSprite, TextureAtlasSprite backSprite ) { PoseStack.Pose pose = poseStack.last(); float f = -width / 2.0F; float g = -height / 2.0F; float h = 0.03125F; float i = backSprite.getU0(); float j = backSprite.getU1(); float k = backSprite.getV0(); float l = backSprite.getV1(); float m = backSprite.getU0(); float n = backSprite.getU1(); float o = backSprite.getV0(); float p = backSprite.getV(0.0625F); float q = backSprite.getU0(); float r = backSprite.getU(0.0625F); float s = backSprite.getV0(); float t = backSprite.getV1(); double d = 1.0 / width; double e = 1.0 / height; for (int u = 0; u < width; u++) { for (int v = 0; v < height; v++) { float w = f + (u + 1); float x = f + u; float y = g + (v + 1); float z = g + v; int aa = lightCoords[u + v * width]; float ab = frontSprite.getU((float)(d * (width - u))); float ac = frontSprite.getU((float)(d * (width - (u + 1)))); float ad = frontSprite.getV((float)(e * (height - v))); float ae = frontSprite.getV((float)(e * (height - (v + 1)))); this.vertex(pose, buffer, w, z, ac, ad, -0.03125F, 0, 0, -1, aa); this.vertex(pose, buffer, x, z, ab, ad, -0.03125F, 0, 0, -1, aa); this.vertex(pose, buffer, x, y, ab, ae, -0.03125F, 0, 0, -1, aa); this.vertex(pose, buffer, w, y, ac, ae, -0.03125F, 0, 0, -1, aa); this.vertex(pose, buffer, w, y, j, k, 0.03125F, 0, 0, 1, aa); this.vertex(pose, buffer, x, y, i, k, 0.03125F, 0, 0, 1, aa); this.vertex(pose, buffer, x, z, i, l, 0.03125F, 0, 0, 1, aa); this.vertex(pose, buffer, w, z, j, l, 0.03125F, 0, 0, 1, aa); this.vertex(pose, buffer, w, y, m, o, -0.03125F, 0, 1, 0, aa); this.vertex(pose, buffer, x, y, n, o, -0.03125F, 0, 1, 0, aa); this.vertex(pose, buffer, x, y, n, p, 0.03125F, 0, 1, 0, aa); this.vertex(pose, buffer, w, y, m, p, 0.03125F, 0, 1, 0, aa); this.vertex(pose, buffer, w, z, m, o, 0.03125F, 0, -1, 0, aa); this.vertex(pose, buffer, x, z, n, o, 0.03125F, 0, -1, 0, aa); this.vertex(pose, buffer, x, z, n, p, -0.03125F, 0, -1, 0, aa); this.vertex(pose, buffer, w, z, m, p, -0.03125F, 0, -1, 0, aa); this.vertex(pose, buffer, w, y, r, s, 0.03125F, -1, 0, 0, aa); this.vertex(pose, buffer, w, z, r, t, 0.03125F, -1, 0, 0, aa); this.vertex(pose, buffer, w, z, q, t, -0.03125F, -1, 0, 0, aa); this.vertex(pose, buffer, w, y, q, s, -0.03125F, -1, 0, 0, aa); this.vertex(pose, buffer, x, y, r, s, -0.03125F, 1, 0, 0, aa); this.vertex(pose, buffer, x, z, r, t, -0.03125F, 1, 0, 0, aa); this.vertex(pose, buffer, x, z, q, t, 0.03125F, 1, 0, 0, aa); this.vertex(pose, buffer, x, y, q, s, 0.03125F, 1, 0, 0, aa); } } } private void vertex( PoseStack.Pose pose, VertexConsumer consumer, float x, float y, float u, float v, float z, int normalX, int normalY, int normalZ, int packedLight ) { consumer.addVertex(pose, x, y, z) .setColor(-1) .setUv(u, v) .setOverlay(OverlayTexture.NO_OVERLAY) .setLight(packedLight) .setNormal(pose, normalX, normalY, normalZ); } }