minecraft-src/net/minecraft/client/renderer/debug/LightSectionDebugRenderer.java
2025-07-04 03:45:38 +03:00

136 lines
6 KiB
Java

package net.minecraft.client.renderer.debug;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import java.time.Duration;
import java.time.Instant;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShapeRenderer;
import net.minecraft.core.Direction;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.lighting.LayerLightSectionStorage.SectionType;
import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape;
import net.minecraft.world.phys.shapes.DiscreteVoxelShape;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Vector4f;
@Environment(EnvType.CLIENT)
public class LightSectionDebugRenderer implements DebugRenderer.SimpleDebugRenderer {
private static final Duration REFRESH_INTERVAL = Duration.ofMillis(500L);
private static final int RADIUS = 10;
private static final Vector4f LIGHT_AND_BLOCKS_COLOR = new Vector4f(1.0F, 1.0F, 0.0F, 0.25F);
private static final Vector4f LIGHT_ONLY_COLOR = new Vector4f(0.25F, 0.125F, 0.0F, 0.125F);
private final Minecraft minecraft;
private final LightLayer lightLayer;
private Instant lastUpdateTime = Instant.now();
@Nullable
private LightSectionDebugRenderer.SectionData data;
public LightSectionDebugRenderer(Minecraft minecraft, LightLayer lightLayer) {
this.minecraft = minecraft;
this.lightLayer = lightLayer;
}
@Override
public void render(PoseStack poseStack, MultiBufferSource bufferSource, double camX, double camY, double camZ) {
Instant instant = Instant.now();
if (this.data == null || Duration.between(this.lastUpdateTime, instant).compareTo(REFRESH_INTERVAL) > 0) {
this.lastUpdateTime = instant;
this.data = new LightSectionDebugRenderer.SectionData(
this.minecraft.level.getLightEngine(), SectionPos.of(this.minecraft.player.blockPosition()), 10, this.lightLayer
);
}
renderEdges(poseStack, this.data.lightAndBlocksShape, this.data.minPos, bufferSource, camX, camY, camZ, LIGHT_AND_BLOCKS_COLOR);
renderEdges(poseStack, this.data.lightShape, this.data.minPos, bufferSource, camX, camY, camZ, LIGHT_ONLY_COLOR);
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.debugSectionQuads());
renderFaces(poseStack, this.data.lightAndBlocksShape, this.data.minPos, vertexConsumer, camX, camY, camZ, LIGHT_AND_BLOCKS_COLOR);
renderFaces(poseStack, this.data.lightShape, this.data.minPos, vertexConsumer, camX, camY, camZ, LIGHT_ONLY_COLOR);
}
private static void renderFaces(
PoseStack poseStack, DiscreteVoxelShape shape, SectionPos pos, VertexConsumer buffer, double camX, double camY, double camZ, Vector4f color
) {
shape.forAllFaces((direction, i, j, k) -> {
int l = i + pos.getX();
int m = j + pos.getY();
int n = k + pos.getZ();
renderFace(poseStack, buffer, direction, camX, camY, camZ, l, m, n, color);
});
}
private static void renderEdges(
PoseStack poseStack, DiscreteVoxelShape shape, SectionPos pos, MultiBufferSource bufferSource, double camX, double camY, double camZ, Vector4f color
) {
shape.forAllEdges((i, j, k, l, m, n) -> {
int o = i + pos.getX();
int p = j + pos.getY();
int q = k + pos.getZ();
int r = l + pos.getX();
int s = m + pos.getY();
int t = n + pos.getZ();
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.debugLineStrip(1.0));
renderEdge(poseStack, vertexConsumer, camX, camY, camZ, o, p, q, r, s, t, color);
}, true);
}
private static void renderFace(
PoseStack poseStack, VertexConsumer buffer, Direction face, double camX, double camY, double camZ, int blockX, int blockY, int blockZ, Vector4f color
) {
float f = (float)(SectionPos.sectionToBlockCoord(blockX) - camX);
float g = (float)(SectionPos.sectionToBlockCoord(blockY) - camY);
float h = (float)(SectionPos.sectionToBlockCoord(blockZ) - camZ);
ShapeRenderer.renderFace(poseStack, buffer, face, f, g, h, f + 16.0F, g + 16.0F, h + 16.0F, color.x(), color.y(), color.z(), color.w());
}
private static void renderEdge(
PoseStack poseStack, VertexConsumer buffer, double camX, double camY, double camZ, int x1, int y1, int z1, int x2, int y2, int z2, Vector4f color
) {
float f = (float)(SectionPos.sectionToBlockCoord(x1) - camX);
float g = (float)(SectionPos.sectionToBlockCoord(y1) - camY);
float h = (float)(SectionPos.sectionToBlockCoord(z1) - camZ);
float i = (float)(SectionPos.sectionToBlockCoord(x2) - camX);
float j = (float)(SectionPos.sectionToBlockCoord(y2) - camY);
float k = (float)(SectionPos.sectionToBlockCoord(z2) - camZ);
Matrix4f matrix4f = poseStack.last().pose();
buffer.addVertex(matrix4f, f, g, h).setColor(color.x(), color.y(), color.z(), 1.0F);
buffer.addVertex(matrix4f, i, j, k).setColor(color.x(), color.y(), color.z(), 1.0F);
}
@Environment(EnvType.CLIENT)
static final class SectionData {
final DiscreteVoxelShape lightAndBlocksShape;
final DiscreteVoxelShape lightShape;
final SectionPos minPos;
SectionData(LevelLightEngine levelLightEngine, SectionPos pos, int radius, LightLayer lightLayer) {
int i = radius * 2 + 1;
this.lightAndBlocksShape = new BitSetDiscreteVoxelShape(i, i, i);
this.lightShape = new BitSetDiscreteVoxelShape(i, i, i);
for (int j = 0; j < i; j++) {
for (int k = 0; k < i; k++) {
for (int l = 0; l < i; l++) {
SectionPos sectionPos = SectionPos.of(pos.x() + l - radius, pos.y() + k - radius, pos.z() + j - radius);
SectionType sectionType = levelLightEngine.getDebugSectionType(lightLayer, sectionPos);
if (sectionType == SectionType.LIGHT_AND_DATA) {
this.lightAndBlocksShape.fill(l, k, j);
this.lightShape.fill(l, k, j);
} else if (sectionType == SectionType.LIGHT_ONLY) {
this.lightShape.fill(l, k, j);
}
}
}
}
this.minPos = SectionPos.of(pos.x() - radius, pos.y() - radius, pos.z() - radius);
}
}
}