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

147 lines
6.1 KiB
Java

package net.minecraft.client.renderer.chunk;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.ByteBufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.MeshData;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexSorting;
import com.mojang.blaze3d.vertex.MeshData.SortState;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.SectionBufferBuilderPack;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.block.model.BlockModelPart;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class SectionCompiler {
private final BlockRenderDispatcher blockRenderer;
private final BlockEntityRenderDispatcher blockEntityRenderer;
public SectionCompiler(BlockRenderDispatcher blockRenderer, BlockEntityRenderDispatcher blockEntityRenderer) {
this.blockRenderer = blockRenderer;
this.blockEntityRenderer = blockEntityRenderer;
}
public SectionCompiler.Results compile(
SectionPos sectionPos, RenderChunkRegion region, VertexSorting vertexSorting, SectionBufferBuilderPack sectionBufferBuilderPack
) {
SectionCompiler.Results results = new SectionCompiler.Results();
BlockPos blockPos = sectionPos.origin();
BlockPos blockPos2 = blockPos.offset(15, 15, 15);
VisGraph visGraph = new VisGraph();
PoseStack poseStack = new PoseStack();
ModelBlockRenderer.enableCaching();
Map<RenderType, BufferBuilder> map = new Reference2ObjectArrayMap<>(RenderType.chunkBufferLayers().size());
RandomSource randomSource = RandomSource.create();
List<BlockModelPart> list = new ObjectArrayList<>();
for (BlockPos blockPos3 : BlockPos.betweenClosed(blockPos, blockPos2)) {
BlockState blockState = region.getBlockState(blockPos3);
if (blockState.isSolidRender()) {
visGraph.setOpaque(blockPos3);
}
if (blockState.hasBlockEntity()) {
BlockEntity blockEntity = region.getBlockEntity(blockPos3);
if (blockEntity != null) {
this.handleBlockEntity(results, blockEntity);
}
}
FluidState fluidState = blockState.getFluidState();
if (!fluidState.isEmpty()) {
RenderType renderType = ItemBlockRenderTypes.getRenderLayer(fluidState);
BufferBuilder bufferBuilder = this.getOrBeginLayer(map, sectionBufferBuilderPack, renderType);
this.blockRenderer.renderLiquid(blockPos3, region, bufferBuilder, blockState, fluidState);
}
if (blockState.getRenderShape() == RenderShape.MODEL) {
RenderType renderType = ItemBlockRenderTypes.getChunkRenderType(blockState);
BufferBuilder bufferBuilder = this.getOrBeginLayer(map, sectionBufferBuilderPack, renderType);
randomSource.setSeed(blockState.getSeed(blockPos3));
this.blockRenderer.getBlockModel(blockState).collectParts(randomSource, list);
poseStack.pushPose();
poseStack.translate(
(float)SectionPos.sectionRelative(blockPos3.getX()),
(float)SectionPos.sectionRelative(blockPos3.getY()),
(float)SectionPos.sectionRelative(blockPos3.getZ())
);
this.blockRenderer.renderBatched(blockState, blockPos3, region, poseStack, bufferBuilder, true, list);
poseStack.popPose();
list.clear();
}
}
for (Entry<RenderType, BufferBuilder> entry : map.entrySet()) {
RenderType renderType2 = (RenderType)entry.getKey();
MeshData meshData = ((BufferBuilder)entry.getValue()).build();
if (meshData != null) {
if (renderType2 == RenderType.translucent()) {
results.transparencyState = meshData.sortQuads(sectionBufferBuilderPack.buffer(RenderType.translucent()), vertexSorting);
}
results.renderedLayers.put(renderType2, meshData);
}
}
ModelBlockRenderer.clearCache();
results.visibilitySet = visGraph.resolve();
return results;
}
private BufferBuilder getOrBeginLayer(Map<RenderType, BufferBuilder> bufferLayers, SectionBufferBuilderPack sectionBufferBuilderPack, RenderType renderType) {
BufferBuilder bufferBuilder = (BufferBuilder)bufferLayers.get(renderType);
if (bufferBuilder == null) {
ByteBufferBuilder byteBufferBuilder = sectionBufferBuilderPack.buffer(renderType);
bufferBuilder = new BufferBuilder(byteBufferBuilder, VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
bufferLayers.put(renderType, bufferBuilder);
}
return bufferBuilder;
}
private <E extends BlockEntity> void handleBlockEntity(SectionCompiler.Results results, E blockEntity) {
BlockEntityRenderer<E> blockEntityRenderer = this.blockEntityRenderer.getRenderer(blockEntity);
if (blockEntityRenderer != null) {
results.blockEntities.add(blockEntity);
if (blockEntityRenderer.shouldRenderOffScreen(blockEntity)) {
results.globalBlockEntities.add(blockEntity);
}
}
}
@Environment(EnvType.CLIENT)
public static final class Results {
public final List<BlockEntity> globalBlockEntities = new ArrayList();
public final List<BlockEntity> blockEntities = new ArrayList();
public final Map<RenderType, MeshData> renderedLayers = new Reference2ObjectArrayMap<>();
public VisibilitySet visibilitySet = new VisibilitySet();
@Nullable
public SortState transparencyState;
public void release() {
this.renderedLayers.values().forEach(MeshData::close);
}
}
}