2025-11-24 22:52:51 +03:00

334 lines
17 KiB
Java

/*
* Decompiled with CFR 0.152.
*/
package net.minecraft.client.renderer.block;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.BiomeColors;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.block.BlockModelShaper;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.MaterialSet;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.Mth;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.HalfTransparentBlock;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class LiquidBlockRenderer {
private static final float MAX_FLUID_HEIGHT = 0.8888889f;
private final TextureAtlasSprite[] lavaIcons = new TextureAtlasSprite[2];
private final TextureAtlasSprite[] waterIcons = new TextureAtlasSprite[2];
private TextureAtlasSprite waterOverlay;
protected void setupSprites(BlockModelShaper blockModelShaper, MaterialSet materials) {
this.lavaIcons[0] = blockModelShaper.getBlockModel(Blocks.LAVA.defaultBlockState()).particleIcon();
this.lavaIcons[1] = materials.get(ModelBakery.LAVA_FLOW);
this.waterIcons[0] = blockModelShaper.getBlockModel(Blocks.WATER.defaultBlockState()).particleIcon();
this.waterIcons[1] = materials.get(ModelBakery.WATER_FLOW);
this.waterOverlay = materials.get(ModelBakery.WATER_OVERLAY);
}
private static boolean isNeighborSameFluid(FluidState fluidState, FluidState neighborFluidState) {
return neighborFluidState.getType().isSame(fluidState.getType());
}
private static boolean isFaceOccludedByState(Direction direction, float height, BlockState state) {
VoxelShape occluder = state.getFaceOcclusionShape(direction.getOpposite());
if (occluder == Shapes.empty()) {
return false;
}
if (occluder == Shapes.block()) {
boolean fullBlock = height == 1.0f;
return direction != Direction.UP || fullBlock;
}
VoxelShape shape = Shapes.box(0.0, 0.0, 0.0, 1.0, height, 1.0);
return Shapes.blockOccludes(shape, occluder, direction);
}
private static boolean isFaceOccludedByNeighbor(Direction direction, float height, BlockState neighborState) {
return LiquidBlockRenderer.isFaceOccludedByState(direction, height, neighborState);
}
private static boolean isFaceOccludedBySelf(BlockState state, Direction direction) {
return LiquidBlockRenderer.isFaceOccludedByState(direction.getOpposite(), 1.0f, state);
}
public static boolean shouldRenderFace(FluidState fluidState, BlockState blockState, Direction direction, FluidState neighborFluidState) {
return !LiquidBlockRenderer.isFaceOccludedBySelf(blockState, direction) && !LiquidBlockRenderer.isNeighborSameFluid(fluidState, neighborFluidState);
}
public void tesselate(BlockAndTintGetter level, BlockPos pos, VertexConsumer builder, BlockState blockState, FluidState fluidState) {
float bottomOffs;
float heightSouthWest;
float heightSouthEast;
float heightNorthWest;
float heightNorthEast;
boolean isLava = fluidState.is(FluidTags.LAVA);
TextureAtlasSprite[] sprites = isLava ? this.lavaIcons : this.waterIcons;
int col = isLava ? 0xFFFFFF : BiomeColors.getAverageWaterColor(level, pos);
float r = (float)(col >> 16 & 0xFF) / 255.0f;
float g = (float)(col >> 8 & 0xFF) / 255.0f;
float b = (float)(col & 0xFF) / 255.0f;
BlockState blockStateDown = level.getBlockState(pos.relative(Direction.DOWN));
FluidState fluidStateDown = blockStateDown.getFluidState();
BlockState blockStateUp = level.getBlockState(pos.relative(Direction.UP));
FluidState fluidStateUp = blockStateUp.getFluidState();
BlockState blockStateNorth = level.getBlockState(pos.relative(Direction.NORTH));
FluidState fluidStateNorth = blockStateNorth.getFluidState();
BlockState blockStateSouth = level.getBlockState(pos.relative(Direction.SOUTH));
FluidState fluidStateSouth = blockStateSouth.getFluidState();
BlockState blockStateWest = level.getBlockState(pos.relative(Direction.WEST));
FluidState fluidStateWest = blockStateWest.getFluidState();
BlockState blockStateEast = level.getBlockState(pos.relative(Direction.EAST));
FluidState fluidStateEast = blockStateEast.getFluidState();
boolean renderUp = !LiquidBlockRenderer.isNeighborSameFluid(fluidState, fluidStateUp);
boolean renderDown = LiquidBlockRenderer.shouldRenderFace(fluidState, blockState, Direction.DOWN, fluidStateDown) && !LiquidBlockRenderer.isFaceOccludedByNeighbor(Direction.DOWN, 0.8888889f, blockStateDown);
boolean renderNorth = LiquidBlockRenderer.shouldRenderFace(fluidState, blockState, Direction.NORTH, fluidStateNorth);
boolean renderSouth = LiquidBlockRenderer.shouldRenderFace(fluidState, blockState, Direction.SOUTH, fluidStateSouth);
boolean renderWest = LiquidBlockRenderer.shouldRenderFace(fluidState, blockState, Direction.WEST, fluidStateWest);
boolean renderEast = LiquidBlockRenderer.shouldRenderFace(fluidState, blockState, Direction.EAST, fluidStateEast);
if (!(renderUp || renderDown || renderEast || renderWest || renderNorth || renderSouth)) {
return;
}
float c10 = level.getShade(Direction.DOWN, true);
float c11 = level.getShade(Direction.UP, true);
float c2 = level.getShade(Direction.NORTH, true);
float c3 = level.getShade(Direction.WEST, true);
Fluid type = fluidState.getType();
float heightSelf = this.getHeight(level, type, pos, blockState, fluidState);
if (heightSelf >= 1.0f) {
heightNorthEast = 1.0f;
heightNorthWest = 1.0f;
heightSouthEast = 1.0f;
heightSouthWest = 1.0f;
} else {
float heightNorth = this.getHeight(level, type, pos.north(), blockStateNorth, fluidStateNorth);
float heightSouth = this.getHeight(level, type, pos.south(), blockStateSouth, fluidStateSouth);
float heightEast = this.getHeight(level, type, pos.east(), blockStateEast, fluidStateEast);
float heightWest = this.getHeight(level, type, pos.west(), blockStateWest, fluidStateWest);
heightNorthEast = this.calculateAverageHeight(level, type, heightSelf, heightNorth, heightEast, pos.relative(Direction.NORTH).relative(Direction.EAST));
heightNorthWest = this.calculateAverageHeight(level, type, heightSelf, heightNorth, heightWest, pos.relative(Direction.NORTH).relative(Direction.WEST));
heightSouthEast = this.calculateAverageHeight(level, type, heightSelf, heightSouth, heightEast, pos.relative(Direction.SOUTH).relative(Direction.EAST));
heightSouthWest = this.calculateAverageHeight(level, type, heightSelf, heightSouth, heightWest, pos.relative(Direction.SOUTH).relative(Direction.WEST));
}
float x = pos.getX() & 0xF;
float y = pos.getY() & 0xF;
float z = pos.getZ() & 0xF;
float offs = 0.001f;
float f = bottomOffs = renderDown ? 0.001f : 0.0f;
if (renderUp && !LiquidBlockRenderer.isFaceOccludedByNeighbor(Direction.UP, Math.min(Math.min(heightNorthWest, heightSouthWest), Math.min(heightSouthEast, heightNorthEast)), blockStateUp)) {
float v11;
float u11;
float v10;
float u10;
float v01;
float u01;
float v00;
float u00;
heightNorthWest -= 0.001f;
heightSouthWest -= 0.001f;
heightSouthEast -= 0.001f;
heightNorthEast -= 0.001f;
Vec3 flow = fluidState.getFlow(level, pos);
if (flow.x == 0.0 && flow.z == 0.0) {
sprite = sprites[0];
u00 = sprite.getU(0.0f);
v00 = sprite.getV(0.0f);
u01 = u00;
v01 = sprite.getV(1.0f);
u10 = sprite.getU(1.0f);
v10 = v01;
u11 = u10;
v11 = v00;
} else {
sprite = sprites[1];
float angle = (float)Mth.atan2(flow.z, flow.x) - 1.5707964f;
float s = Mth.sin(angle) * 0.25f;
float c = Mth.cos(angle) * 0.25f;
float cc = 0.5f;
u00 = sprite.getU(0.5f + (-c - s));
v00 = sprite.getV(0.5f + (-c + s));
u01 = sprite.getU(0.5f + (-c + s));
v01 = sprite.getV(0.5f + (c + s));
u10 = sprite.getU(0.5f + (c + s));
v10 = sprite.getV(0.5f + (c - s));
u11 = sprite.getU(0.5f + (c - s));
v11 = sprite.getV(0.5f + (-c - s));
}
int topColor = this.getLightColor(level, pos);
float topRed = c11 * r;
float topGreen = c11 * g;
float topBlue = c11 * b;
this.vertex(builder, x + 0.0f, y + heightNorthWest, z + 0.0f, topRed, topGreen, topBlue, u00, v00, topColor);
this.vertex(builder, x + 0.0f, y + heightSouthWest, z + 1.0f, topRed, topGreen, topBlue, u01, v01, topColor);
this.vertex(builder, x + 1.0f, y + heightSouthEast, z + 1.0f, topRed, topGreen, topBlue, u10, v10, topColor);
this.vertex(builder, x + 1.0f, y + heightNorthEast, z + 0.0f, topRed, topGreen, topBlue, u11, v11, topColor);
if (fluidState.shouldRenderBackwardUpFace(level, pos.above())) {
this.vertex(builder, x + 0.0f, y + heightNorthWest, z + 0.0f, topRed, topGreen, topBlue, u00, v00, topColor);
this.vertex(builder, x + 1.0f, y + heightNorthEast, z + 0.0f, topRed, topGreen, topBlue, u11, v11, topColor);
this.vertex(builder, x + 1.0f, y + heightSouthEast, z + 1.0f, topRed, topGreen, topBlue, u10, v10, topColor);
this.vertex(builder, x + 0.0f, y + heightSouthWest, z + 1.0f, topRed, topGreen, topBlue, u01, v01, topColor);
}
}
if (renderDown) {
float u0 = sprites[0].getU0();
float u1 = sprites[0].getU1();
float v0 = sprites[0].getV0();
float v1 = sprites[0].getV1();
int belowColor = this.getLightColor(level, pos.below());
float belowRed = c10 * r;
float belowGreen = c10 * g;
float belowBlue = c10 * b;
this.vertex(builder, x, y + bottomOffs, z + 1.0f, belowRed, belowGreen, belowBlue, u0, v1, belowColor);
this.vertex(builder, x, y + bottomOffs, z, belowRed, belowGreen, belowBlue, u0, v0, belowColor);
this.vertex(builder, x + 1.0f, y + bottomOffs, z, belowRed, belowGreen, belowBlue, u1, v0, belowColor);
this.vertex(builder, x + 1.0f, y + bottomOffs, z + 1.0f, belowRed, belowGreen, belowBlue, u1, v1, belowColor);
}
int sideColor = this.getLightColor(level, pos);
for (Direction faceDir : Direction.Plane.HORIZONTAL) {
Block relativeBlock;
float z1;
float z0;
float x1;
float x0;
float hh1;
float hh0;
if (!(switch (faceDir) {
case Direction.NORTH -> {
hh0 = heightNorthWest;
hh1 = heightNorthEast;
x0 = x;
x1 = x + 1.0f;
z0 = z + 0.001f;
z1 = z + 0.001f;
yield renderNorth;
}
case Direction.SOUTH -> {
hh0 = heightSouthEast;
hh1 = heightSouthWest;
x0 = x + 1.0f;
x1 = x;
z0 = z + 1.0f - 0.001f;
z1 = z + 1.0f - 0.001f;
yield renderSouth;
}
case Direction.WEST -> {
hh0 = heightSouthWest;
hh1 = heightNorthWest;
x0 = x + 0.001f;
x1 = x + 0.001f;
z0 = z + 1.0f;
z1 = z;
yield renderWest;
}
default -> {
hh0 = heightNorthEast;
hh1 = heightSouthEast;
x0 = x + 1.0f - 0.001f;
x1 = x + 1.0f - 0.001f;
z0 = z;
z1 = z + 1.0f;
yield renderEast;
}
}) || LiquidBlockRenderer.isFaceOccludedByNeighbor(faceDir, Math.max(hh0, hh1), level.getBlockState(pos.relative(faceDir)))) continue;
BlockPos tPos = pos.relative(faceDir);
TextureAtlasSprite sprite = sprites[1];
if (!isLava && ((relativeBlock = level.getBlockState(tPos).getBlock()) instanceof HalfTransparentBlock || relativeBlock instanceof LeavesBlock)) {
sprite = this.waterOverlay;
}
float u0 = sprite.getU(0.0f);
float u1 = sprite.getU(0.5f);
float v01 = sprite.getV((1.0f - hh0) * 0.5f);
float v02 = sprite.getV((1.0f - hh1) * 0.5f);
float v1 = sprite.getV(0.5f);
float br = faceDir.getAxis() == Direction.Axis.Z ? c2 : c3;
float red = c11 * br * r;
float green = c11 * br * g;
float blue = c11 * br * b;
this.vertex(builder, x0, y + hh0, z0, red, green, blue, u0, v01, sideColor);
this.vertex(builder, x1, y + hh1, z1, red, green, blue, u1, v02, sideColor);
this.vertex(builder, x1, y + bottomOffs, z1, red, green, blue, u1, v1, sideColor);
this.vertex(builder, x0, y + bottomOffs, z0, red, green, blue, u0, v1, sideColor);
if (sprite == this.waterOverlay) continue;
this.vertex(builder, x0, y + bottomOffs, z0, red, green, blue, u0, v1, sideColor);
this.vertex(builder, x1, y + bottomOffs, z1, red, green, blue, u1, v1, sideColor);
this.vertex(builder, x1, y + hh1, z1, red, green, blue, u1, v02, sideColor);
this.vertex(builder, x0, y + hh0, z0, red, green, blue, u0, v01, sideColor);
}
}
private float calculateAverageHeight(BlockAndTintGetter level, Fluid type, float heightSelf, float height2, float height1, BlockPos cornerPos) {
if (height1 >= 1.0f || height2 >= 1.0f) {
return 1.0f;
}
float[] weightedHeight = new float[2];
if (height1 > 0.0f || height2 > 0.0f) {
float heightCorner = this.getHeight(level, type, cornerPos);
if (heightCorner >= 1.0f) {
return 1.0f;
}
this.addWeightedHeight(weightedHeight, heightCorner);
}
this.addWeightedHeight(weightedHeight, heightSelf);
this.addWeightedHeight(weightedHeight, height1);
this.addWeightedHeight(weightedHeight, height2);
return weightedHeight[0] / weightedHeight[1];
}
private void addWeightedHeight(float[] weightedHeight, float height) {
if (height >= 0.8f) {
weightedHeight[0] = weightedHeight[0] + height * 10.0f;
weightedHeight[1] = weightedHeight[1] + 10.0f;
} else if (height >= 0.0f) {
weightedHeight[0] = weightedHeight[0] + height;
weightedHeight[1] = weightedHeight[1] + 1.0f;
}
}
private float getHeight(BlockAndTintGetter level, Fluid fluidType, BlockPos pos) {
BlockState state = level.getBlockState(pos);
return this.getHeight(level, fluidType, pos, state, state.getFluidState());
}
private float getHeight(BlockAndTintGetter level, Fluid fluidType, BlockPos pos, BlockState state, FluidState fluidState) {
if (fluidType.isSame(fluidState.getType())) {
BlockState aboveState = level.getBlockState(pos.above());
if (fluidType.isSame(aboveState.getFluidState().getType())) {
return 1.0f;
}
return fluidState.getOwnHeight();
}
if (!state.isSolid()) {
return 0.0f;
}
return -1.0f;
}
private void vertex(VertexConsumer builder, float x, float y, float z, float red, float green, float blue, float u, float v, int light) {
builder.addVertex(x, y, z).setColor(red, green, blue, 1.0f).setUv(u, v).setLight(light).setNormal(0.0f, 1.0f, 0.0f);
}
private int getLightColor(BlockAndTintGetter level, BlockPos pos) {
int a = LevelRenderer.getLightColor(level, pos);
int b = LevelRenderer.getLightColor(level, pos.above());
int aa = a & 0xFF;
int ba = b & 0xFF;
int ab = a >> 16 & 0xFF;
int bb = b >> 16 & 0xFF;
return (aa > ba ? aa : ba) | (ab > bb ? ab : bb) << 16;
}
}