]> git.lizzy.rs Git - LightOverlay.git/blob - common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayRenderer.java
1.19.4
[LightOverlay.git] / common / src / main / java / me / shedaniel / lightoverlay / common / LightOverlayRenderer.java
1 package me.shedaniel.lightoverlay.common;
2
3 import com.mojang.blaze3d.systems.RenderSystem;
4 import com.mojang.blaze3d.vertex.*;
5 import it.unimi.dsi.fastutil.longs.Long2ByteMap;
6 import net.minecraft.client.Camera;
7 import net.minecraft.client.Minecraft;
8 import net.minecraft.client.gui.Font;
9 import net.minecraft.client.player.LocalPlayer;
10 import net.minecraft.client.renderer.GameRenderer;
11 import net.minecraft.client.renderer.MultiBufferSource;
12 import net.minecraft.client.renderer.culling.Frustum;
13 import net.minecraft.core.BlockPos;
14 import net.minecraft.core.Direction;
15 import net.minecraft.util.Mth;
16 import net.minecraft.world.level.Level;
17 import net.minecraft.world.phys.AABB;
18 import net.minecraft.world.phys.shapes.CollisionContext;
19 import net.minecraft.world.phys.shapes.VoxelShape;
20 import org.joml.Matrix4f;
21 import org.joml.Quaternionf;
22
23 import java.util.Map;
24 import java.util.function.Consumer;
25
26 public class LightOverlayRenderer implements Consumer<PoseStack> {
27     private final Minecraft minecraft = Minecraft.getInstance();
28     public Frustum frustum;
29     public LightOverlayTicker ticker;
30     
31     public LightOverlayRenderer(LightOverlayTicker ticker) {
32         this.ticker = ticker;
33     }
34     
35     @Override
36     public void accept(PoseStack poses) {
37         if (LightOverlay.enabled) {
38             LocalPlayer playerEntity = minecraft.player;
39             BlockPos playerPos = BlockPos.containing(playerEntity.getX(), playerEntity.getY(), playerEntity.getZ());
40             int playerPosX = playerPos.getX() >> 4;
41             int playerPosY = playerPos.getY() >> 5;
42             int playerPosZ = playerPos.getZ() >> 4;
43             CollisionContext collisionContext = CollisionContext.of(playerEntity);
44             Camera camera = minecraft.gameRenderer.getMainCamera();
45             int chunkRange = LightOverlay.getChunkRange();
46             
47             if (LightOverlay.showNumber) {
48                 renderLevels(poses, camera, playerPos, playerPosX, playerPosY, playerPosZ, chunkRange, collisionContext);
49             } else {
50                 renderCrosses(poses, camera, playerPos, playerPosX, playerPosY, playerPosZ, chunkRange, collisionContext);
51             }
52         }
53     }
54     
55     private void renderLevels(PoseStack poses, Camera camera, BlockPos playerPos, int playerPosX, int playerPosY, int playerPosZ, int chunkRange, CollisionContext collisionContext) {
56         RenderSystem.depthMask(true);
57         BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
58         BlockPos.MutableBlockPos downMutable = new BlockPos.MutableBlockPos();
59         MultiBufferSource.BufferSource source = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
60         for (Map.Entry<CubicChunkPos, Long2ByteMap> entry : ticker.CHUNK_MAP.entrySet()) {
61             CubicChunkPos chunkPos = entry.getKey();
62             if (LightOverlay.caching && (Mth.abs(chunkPos.x - playerPosX) > chunkRange || Mth.abs(chunkPos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(chunkPos.z - playerPosZ) > chunkRange)) {
63                 continue;
64             }
65             for (Long2ByteMap.Entry objectEntry : entry.getValue().long2ByteEntrySet()) {
66                 mutable.set(objectEntry.getLongKey());
67                 if (mutable.closerThan(playerPos, LightOverlay.reach)) {
68                     if (isFrustumVisible(mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
69                         downMutable.set(mutable.getX(), mutable.getY() - 1, mutable.getZ());
70                         renderLevel(poses, source, camera, minecraft.level, mutable, downMutable, objectEntry.getByteValue(), collisionContext);
71                     }
72                 }
73             }
74         }
75         RenderSystem.enableDepthTest();
76         source.endBatch();
77     }
78     
79     public void renderLevel(PoseStack poses, MultiBufferSource.BufferSource source, Camera camera, Level world, BlockPos pos, BlockPos down, byte level, CollisionContext collisionContext) {
80         String text = String.valueOf(level);
81         Font font = minecraft.font;
82         double cameraX = camera.getPosition().x;
83         double cameraY = camera.getPosition().y;
84         VoxelShape upperOutlineShape = world.getBlockState(down).getShape(world, down, collisionContext);
85         if (!upperOutlineShape.isEmpty())
86             cameraY += 1 - upperOutlineShape.max(Direction.Axis.Y);
87         double cameraZ = camera.getPosition().z;
88         poses.pushPose();
89         poses.translate(pos.getX() + 0.5 - cameraX, pos.getY() - cameraY + 0.005, pos.getZ() + 0.5 - cameraZ);
90         poses.mulPose(new Quaternionf().fromAxisAngleDeg(1, 0, 0, 90));
91 //        poses.glNormal3f(0.0F, 1.0F, 0.0F);
92         float size = 0.07F;
93         poses.scale(-size, -size, size);
94         float float_3 = (float) (-font.width(text)) / 2.0F + 0.4f;
95         font.drawInBatch(text, float_3, -3.5f, level > LightOverlay.higherCrossLevel ? 0xff042404 : (LightOverlay.lowerCrossLevel >= 0 && level > LightOverlay.lowerCrossLevel ? 0xff0066ff : 0xff731111), false, poses.last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880);
96         poses.popPose();
97     }
98     
99     private void renderCrosses(PoseStack poses, Camera camera, BlockPos playerPos, int playerPosX, int playerPosY, int playerPosZ, int chunkRange, CollisionContext collisionContext) {
100         RenderSystem.enableDepthTest();
101         RenderSystem.disableBlend();
102         RenderSystem.setShader(GameRenderer::getPositionColorShader);
103         RenderSystem.lineWidth(LightOverlay.lineWidth);
104         Tesselator tesselator = Tesselator.getInstance();
105         BufferBuilder builder = tesselator.getBuilder();
106         builder.begin(VertexFormat.Mode.DEBUG_LINES, DefaultVertexFormat.POSITION_COLOR);
107         BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
108         
109         for (Map.Entry<CubicChunkPos, Long2ByteMap> entry : ticker.CHUNK_MAP.entrySet()) {
110             CubicChunkPos chunkPos = entry.getKey();
111             if (LightOverlay.caching && (Mth.abs(chunkPos.x - playerPosX) > chunkRange || Mth.abs(chunkPos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(chunkPos.z - playerPosZ) > chunkRange)) {
112                 continue;
113             }
114             
115             for (Long2ByteMap.Entry objectEntry : entry.getValue().long2ByteEntrySet()) {
116                 byte crossType = objectEntry.getByteValue();
117                 mutable.set(objectEntry.getLongKey());
118                 if (mutable.closerThan(playerPos, LightOverlay.reach)) {
119                     if (isFrustumVisible(mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
120                         int color = switch (crossType) {
121                             case LightOverlay.CROSS_RED -> LightOverlay.redColor;
122                             case LightOverlay.CROSS_YELLOW -> LightOverlay.yellowColor;
123                             default -> LightOverlay.secondaryColor;
124                         };
125                         renderCross(poses.last().pose(), builder, camera, minecraft.level, mutable, color, collisionContext);
126                     }
127                 }
128             }
129         }
130         
131         tesselator.end();
132         RenderSystem.lineWidth(1.0F);
133         RenderSystem.enableBlend();
134     }
135     
136     public void renderCross(Matrix4f pose, BufferBuilder builder, Camera camera, Level world, BlockPos pos, int color, CollisionContext collisionContext) {
137         double cameraX = camera.getPosition().x;
138         double cameraY = camera.getPosition().y - .005D;
139         double blockOffset = 0;
140         VoxelShape upperOutlineShape = world.getBlockState(pos).getShape(world, pos, collisionContext);
141         if (!upperOutlineShape.isEmpty()) {
142             blockOffset += upperOutlineShape.max(Direction.Axis.Y);
143         }
144         double cameraZ = camera.getPosition().z;
145         
146         int red = (color >> 16) & 255;
147         int green = (color >> 8) & 255;
148         int blue = color & 255;
149         double x = pos.getX() - cameraX;
150         double y = pos.getY() - cameraY + blockOffset;
151         double z = pos.getZ() - cameraZ;
152         builder.vertex(pose, (float)(x + .01D), (float)y, (float)(z + .01D)).color(red, green, blue, 255).endVertex();
153         builder.vertex(pose, (float)(x + .99D), (float)y, (float)(z + .99D)).color(red, green, blue, 255).endVertex();
154         builder.vertex(pose, (float)(x + .99D), (float)y, (float)(z + .01D)).color(red, green, blue, 255).endVertex();
155         builder.vertex(pose, (float)(x + .01D), (float)y, (float)(z + .99D)).color(red, green, blue, 255).endVertex();
156     }
157     
158     public boolean isFrustumVisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
159         return frustum.isVisible(new AABB(minX, minY, minZ, maxX, maxY, maxZ));
160     }
161 }