334 lines
17 KiB
Java
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;
|
|
}
|
|
}
|
|
|