350 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.block;
 | |
| 
 | |
| import com.mojang.blaze3d.vertex.VertexConsumer;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.Minecraft;
 | |
| import net.minecraft.client.renderer.BiomeColors;
 | |
| import net.minecraft.client.renderer.LevelRenderer;
 | |
| import net.minecraft.client.renderer.texture.TextureAtlasSprite;
 | |
| 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;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| 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() {
 | |
| 		this.lavaIcons[0] = Minecraft.getInstance().getModelManager().getBlockModelShaper().getBlockModel(Blocks.LAVA.defaultBlockState()).particleIcon();
 | |
| 		this.lavaIcons[1] = ModelBakery.LAVA_FLOW.sprite();
 | |
| 		this.waterIcons[0] = Minecraft.getInstance().getModelManager().getBlockModelShaper().getBlockModel(Blocks.WATER.defaultBlockState()).particleIcon();
 | |
| 		this.waterIcons[1] = ModelBakery.WATER_FLOW.sprite();
 | |
| 		this.waterOverlay = ModelBakery.WATER_OVERLAY.sprite();
 | |
| 	}
 | |
| 
 | |
| 	private static boolean isNeighborSameFluid(FluidState firstState, FluidState secondState) {
 | |
| 		return secondState.getType().isSame(firstState.getType());
 | |
| 	}
 | |
| 
 | |
| 	private static boolean isFaceOccludedByState(Direction face, float height, BlockState state) {
 | |
| 		VoxelShape voxelShape = state.getFaceOcclusionShape(face.getOpposite());
 | |
| 		if (voxelShape == Shapes.empty()) {
 | |
| 			return false;
 | |
| 		} else if (voxelShape == Shapes.block()) {
 | |
| 			boolean bl = height == 1.0F;
 | |
| 			return face != Direction.UP || bl;
 | |
| 		} else {
 | |
| 			VoxelShape voxelShape2 = Shapes.box(0.0, 0.0, 0.0, 1.0, height, 1.0);
 | |
| 			return Shapes.blockOccludes(voxelShape2, voxelShape, face);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static boolean isFaceOccludedByNeighbor(Direction face, float height, BlockState state) {
 | |
| 		return isFaceOccludedByState(face, height, state);
 | |
| 	}
 | |
| 
 | |
| 	private static boolean isFaceOccludedBySelf(BlockState state, Direction face) {
 | |
| 		return isFaceOccludedByState(face.getOpposite(), 1.0F, state);
 | |
| 	}
 | |
| 
 | |
| 	public static boolean shouldRenderFace(FluidState fluidState, BlockState blockState, Direction side, FluidState neighborFluid) {
 | |
| 		return !isFaceOccludedBySelf(blockState, side) && !isNeighborSameFluid(fluidState, neighborFluid);
 | |
| 	}
 | |
| 
 | |
| 	public void tesselate(BlockAndTintGetter level, BlockPos pos, VertexConsumer buffer, BlockState blockState, FluidState fluidState) {
 | |
| 		boolean bl = fluidState.is(FluidTags.LAVA);
 | |
| 		TextureAtlasSprite[] textureAtlasSprites = bl ? this.lavaIcons : this.waterIcons;
 | |
| 		int i = bl ? 16777215 : BiomeColors.getAverageWaterColor(level, pos);
 | |
| 		float f = (i >> 16 & 0xFF) / 255.0F;
 | |
| 		float g = (i >> 8 & 0xFF) / 255.0F;
 | |
| 		float h = (i & 0xFF) / 255.0F;
 | |
| 		BlockState blockState2 = level.getBlockState(pos.relative(Direction.DOWN));
 | |
| 		FluidState fluidState2 = blockState2.getFluidState();
 | |
| 		BlockState blockState3 = level.getBlockState(pos.relative(Direction.UP));
 | |
| 		FluidState fluidState3 = blockState3.getFluidState();
 | |
| 		BlockState blockState4 = level.getBlockState(pos.relative(Direction.NORTH));
 | |
| 		FluidState fluidState4 = blockState4.getFluidState();
 | |
| 		BlockState blockState5 = level.getBlockState(pos.relative(Direction.SOUTH));
 | |
| 		FluidState fluidState5 = blockState5.getFluidState();
 | |
| 		BlockState blockState6 = level.getBlockState(pos.relative(Direction.WEST));
 | |
| 		FluidState fluidState6 = blockState6.getFluidState();
 | |
| 		BlockState blockState7 = level.getBlockState(pos.relative(Direction.EAST));
 | |
| 		FluidState fluidState7 = blockState7.getFluidState();
 | |
| 		boolean bl2 = !isNeighborSameFluid(fluidState, fluidState3);
 | |
| 		boolean bl3 = shouldRenderFace(fluidState, blockState, Direction.DOWN, fluidState2) && !isFaceOccludedByNeighbor(Direction.DOWN, 0.8888889F, blockState2);
 | |
| 		boolean bl4 = shouldRenderFace(fluidState, blockState, Direction.NORTH, fluidState4);
 | |
| 		boolean bl5 = shouldRenderFace(fluidState, blockState, Direction.SOUTH, fluidState5);
 | |
| 		boolean bl6 = shouldRenderFace(fluidState, blockState, Direction.WEST, fluidState6);
 | |
| 		boolean bl7 = shouldRenderFace(fluidState, blockState, Direction.EAST, fluidState7);
 | |
| 		if (bl2 || bl3 || bl7 || bl6 || bl4 || bl5) {
 | |
| 			float j = level.getShade(Direction.DOWN, true);
 | |
| 			float k = level.getShade(Direction.UP, true);
 | |
| 			float l = level.getShade(Direction.NORTH, true);
 | |
| 			float m = level.getShade(Direction.WEST, true);
 | |
| 			Fluid fluid = fluidState.getType();
 | |
| 			float n = this.getHeight(level, fluid, pos, blockState, fluidState);
 | |
| 			float o;
 | |
| 			float p;
 | |
| 			float q;
 | |
| 			float r;
 | |
| 			if (n >= 1.0F) {
 | |
| 				o = 1.0F;
 | |
| 				p = 1.0F;
 | |
| 				q = 1.0F;
 | |
| 				r = 1.0F;
 | |
| 			} else {
 | |
| 				float s = this.getHeight(level, fluid, pos.north(), blockState4, fluidState4);
 | |
| 				float t = this.getHeight(level, fluid, pos.south(), blockState5, fluidState5);
 | |
| 				float u = this.getHeight(level, fluid, pos.east(), blockState7, fluidState7);
 | |
| 				float v = this.getHeight(level, fluid, pos.west(), blockState6, fluidState6);
 | |
| 				o = this.calculateAverageHeight(level, fluid, n, s, u, pos.relative(Direction.NORTH).relative(Direction.EAST));
 | |
| 				p = this.calculateAverageHeight(level, fluid, n, s, v, pos.relative(Direction.NORTH).relative(Direction.WEST));
 | |
| 				q = this.calculateAverageHeight(level, fluid, n, t, u, pos.relative(Direction.SOUTH).relative(Direction.EAST));
 | |
| 				r = this.calculateAverageHeight(level, fluid, n, t, v, pos.relative(Direction.SOUTH).relative(Direction.WEST));
 | |
| 			}
 | |
| 
 | |
| 			float s = pos.getX() & 15;
 | |
| 			float t = pos.getY() & 15;
 | |
| 			float u = pos.getZ() & 15;
 | |
| 			float v = 0.001F;
 | |
| 			float w = bl3 ? 0.001F : 0.0F;
 | |
| 			if (bl2 && !isFaceOccludedByNeighbor(Direction.UP, Math.min(Math.min(p, r), Math.min(q, o)), blockState3)) {
 | |
| 				p -= 0.001F;
 | |
| 				r -= 0.001F;
 | |
| 				q -= 0.001F;
 | |
| 				o -= 0.001F;
 | |
| 				Vec3 vec3 = fluidState.getFlow(level, pos);
 | |
| 				float x;
 | |
| 				float z;
 | |
| 				float ab;
 | |
| 				float ad;
 | |
| 				float y;
 | |
| 				float aa;
 | |
| 				float ac;
 | |
| 				float ae;
 | |
| 				if (vec3.x == 0.0 && vec3.z == 0.0) {
 | |
| 					TextureAtlasSprite textureAtlasSprite = textureAtlasSprites[0];
 | |
| 					x = textureAtlasSprite.getU(0.0F);
 | |
| 					y = textureAtlasSprite.getV(0.0F);
 | |
| 					z = x;
 | |
| 					aa = textureAtlasSprite.getV(1.0F);
 | |
| 					ab = textureAtlasSprite.getU(1.0F);
 | |
| 					ac = aa;
 | |
| 					ad = ab;
 | |
| 					ae = y;
 | |
| 				} else {
 | |
| 					TextureAtlasSprite textureAtlasSprite = textureAtlasSprites[1];
 | |
| 					float af = (float)Mth.atan2(vec3.z, vec3.x) - (float) (Math.PI / 2);
 | |
| 					float ag = Mth.sin(af) * 0.25F;
 | |
| 					float ah = Mth.cos(af) * 0.25F;
 | |
| 					float ai = 0.5F;
 | |
| 					x = textureAtlasSprite.getU(0.5F + (-ah - ag));
 | |
| 					y = textureAtlasSprite.getV(0.5F + (-ah + ag));
 | |
| 					z = textureAtlasSprite.getU(0.5F + (-ah + ag));
 | |
| 					aa = textureAtlasSprite.getV(0.5F + (ah + ag));
 | |
| 					ab = textureAtlasSprite.getU(0.5F + (ah + ag));
 | |
| 					ac = textureAtlasSprite.getV(0.5F + (ah - ag));
 | |
| 					ad = textureAtlasSprite.getU(0.5F + (ah - ag));
 | |
| 					ae = textureAtlasSprite.getV(0.5F + (-ah - ag));
 | |
| 				}
 | |
| 
 | |
| 				float aj = (x + z + ab + ad) / 4.0F;
 | |
| 				float af = (y + aa + ac + ae) / 4.0F;
 | |
| 				float ag = textureAtlasSprites[0].uvShrinkRatio();
 | |
| 				x = Mth.lerp(ag, x, aj);
 | |
| 				z = Mth.lerp(ag, z, aj);
 | |
| 				ab = Mth.lerp(ag, ab, aj);
 | |
| 				ad = Mth.lerp(ag, ad, aj);
 | |
| 				y = Mth.lerp(ag, y, af);
 | |
| 				aa = Mth.lerp(ag, aa, af);
 | |
| 				ac = Mth.lerp(ag, ac, af);
 | |
| 				ae = Mth.lerp(ag, ae, af);
 | |
| 				int ak = this.getLightColor(level, pos);
 | |
| 				float ai = k * f;
 | |
| 				float al = k * g;
 | |
| 				float am = k * h;
 | |
| 				this.vertex(buffer, s + 0.0F, t + p, u + 0.0F, ai, al, am, x, y, ak);
 | |
| 				this.vertex(buffer, s + 0.0F, t + r, u + 1.0F, ai, al, am, z, aa, ak);
 | |
| 				this.vertex(buffer, s + 1.0F, t + q, u + 1.0F, ai, al, am, ab, ac, ak);
 | |
| 				this.vertex(buffer, s + 1.0F, t + o, u + 0.0F, ai, al, am, ad, ae, ak);
 | |
| 				if (fluidState.shouldRenderBackwardUpFace(level, pos.above())) {
 | |
| 					this.vertex(buffer, s + 0.0F, t + p, u + 0.0F, ai, al, am, x, y, ak);
 | |
| 					this.vertex(buffer, s + 1.0F, t + o, u + 0.0F, ai, al, am, ad, ae, ak);
 | |
| 					this.vertex(buffer, s + 1.0F, t + q, u + 1.0F, ai, al, am, ab, ac, ak);
 | |
| 					this.vertex(buffer, s + 0.0F, t + r, u + 1.0F, ai, al, am, z, aa, ak);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (bl3) {
 | |
| 				float xx = textureAtlasSprites[0].getU0();
 | |
| 				float zx = textureAtlasSprites[0].getU1();
 | |
| 				float abx = textureAtlasSprites[0].getV0();
 | |
| 				float adx = textureAtlasSprites[0].getV1();
 | |
| 				int an = this.getLightColor(level, pos.below());
 | |
| 				float aax = j * f;
 | |
| 				float acx = j * g;
 | |
| 				float aex = j * h;
 | |
| 				this.vertex(buffer, s, t + w, u + 1.0F, aax, acx, aex, xx, adx, an);
 | |
| 				this.vertex(buffer, s, t + w, u, aax, acx, aex, xx, abx, an);
 | |
| 				this.vertex(buffer, s + 1.0F, t + w, u, aax, acx, aex, zx, abx, an);
 | |
| 				this.vertex(buffer, s + 1.0F, t + w, u + 1.0F, aax, acx, aex, zx, adx, an);
 | |
| 			}
 | |
| 
 | |
| 			int ao = this.getLightColor(level, pos);
 | |
| 
 | |
| 			for (Direction direction : Direction.Plane.HORIZONTAL) {
 | |
| 				float adx;
 | |
| 				float yx;
 | |
| 				float aax;
 | |
| 				float acx;
 | |
| 				float aex;
 | |
| 				float ap;
 | |
| 				boolean bl8;
 | |
| 				switch (direction) {
 | |
| 					case NORTH:
 | |
| 						adx = p;
 | |
| 						yx = o;
 | |
| 						aax = s;
 | |
| 						aex = s + 1.0F;
 | |
| 						acx = u + 0.001F;
 | |
| 						ap = u + 0.001F;
 | |
| 						bl8 = bl4;
 | |
| 						break;
 | |
| 					case SOUTH:
 | |
| 						adx = q;
 | |
| 						yx = r;
 | |
| 						aax = s + 1.0F;
 | |
| 						aex = s;
 | |
| 						acx = u + 1.0F - 0.001F;
 | |
| 						ap = u + 1.0F - 0.001F;
 | |
| 						bl8 = bl5;
 | |
| 						break;
 | |
| 					case WEST:
 | |
| 						adx = r;
 | |
| 						yx = p;
 | |
| 						aax = s + 0.001F;
 | |
| 						aex = s + 0.001F;
 | |
| 						acx = u + 1.0F;
 | |
| 						ap = u;
 | |
| 						bl8 = bl6;
 | |
| 						break;
 | |
| 					default:
 | |
| 						adx = o;
 | |
| 						yx = q;
 | |
| 						aax = s + 1.0F - 0.001F;
 | |
| 						aex = s + 1.0F - 0.001F;
 | |
| 						acx = u;
 | |
| 						ap = u + 1.0F;
 | |
| 						bl8 = bl7;
 | |
| 				}
 | |
| 
 | |
| 				if (bl8 && !isFaceOccludedByNeighbor(direction, Math.max(adx, yx), level.getBlockState(pos.relative(direction)))) {
 | |
| 					BlockPos blockPos = pos.relative(direction);
 | |
| 					TextureAtlasSprite textureAtlasSprite2 = textureAtlasSprites[1];
 | |
| 					if (!bl) {
 | |
| 						Block block = level.getBlockState(blockPos).getBlock();
 | |
| 						if (block instanceof HalfTransparentBlock || block instanceof LeavesBlock) {
 | |
| 							textureAtlasSprite2 = this.waterOverlay;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					float ah = textureAtlasSprite2.getU(0.0F);
 | |
| 					float ai = textureAtlasSprite2.getU(0.5F);
 | |
| 					float al = textureAtlasSprite2.getV((1.0F - adx) * 0.5F);
 | |
| 					float am = textureAtlasSprite2.getV((1.0F - yx) * 0.5F);
 | |
| 					float aq = textureAtlasSprite2.getV(0.5F);
 | |
| 					float ar = direction.getAxis() == Direction.Axis.Z ? l : m;
 | |
| 					float as = k * ar * f;
 | |
| 					float at = k * ar * g;
 | |
| 					float au = k * ar * h;
 | |
| 					this.vertex(buffer, aax, t + adx, acx, as, at, au, ah, al, ao);
 | |
| 					this.vertex(buffer, aex, t + yx, ap, as, at, au, ai, am, ao);
 | |
| 					this.vertex(buffer, aex, t + w, ap, as, at, au, ai, aq, ao);
 | |
| 					this.vertex(buffer, aax, t + w, acx, as, at, au, ah, aq, ao);
 | |
| 					if (textureAtlasSprite2 != this.waterOverlay) {
 | |
| 						this.vertex(buffer, aax, t + w, acx, as, at, au, ah, aq, ao);
 | |
| 						this.vertex(buffer, aex, t + w, ap, as, at, au, ai, aq, ao);
 | |
| 						this.vertex(buffer, aex, t + yx, ap, as, at, au, ai, am, ao);
 | |
| 						this.vertex(buffer, aax, t + adx, acx, as, at, au, ah, al, ao);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private float calculateAverageHeight(BlockAndTintGetter level, Fluid fluid, float currentHeight, float height1, float height2, BlockPos pos) {
 | |
| 		if (!(height2 >= 1.0F) && !(height1 >= 1.0F)) {
 | |
| 			float[] fs = new float[2];
 | |
| 			if (height2 > 0.0F || height1 > 0.0F) {
 | |
| 				float f = this.getHeight(level, fluid, pos);
 | |
| 				if (f >= 1.0F) {
 | |
| 					return 1.0F;
 | |
| 				}
 | |
| 
 | |
| 				this.addWeightedHeight(fs, f);
 | |
| 			}
 | |
| 
 | |
| 			this.addWeightedHeight(fs, currentHeight);
 | |
| 			this.addWeightedHeight(fs, height2);
 | |
| 			this.addWeightedHeight(fs, height1);
 | |
| 			return fs[0] / fs[1];
 | |
| 		} else {
 | |
| 			return 1.0F;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void addWeightedHeight(float[] output, float height) {
 | |
| 		if (height >= 0.8F) {
 | |
| 			output[0] += height * 10.0F;
 | |
| 			output[1] += 10.0F;
 | |
| 		} else if (height >= 0.0F) {
 | |
| 			output[0] += height;
 | |
| 			output[1]++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private float getHeight(BlockAndTintGetter level, Fluid fluid, BlockPos pos) {
 | |
| 		BlockState blockState = level.getBlockState(pos);
 | |
| 		return this.getHeight(level, fluid, pos, blockState, blockState.getFluidState());
 | |
| 	}
 | |
| 
 | |
| 	private float getHeight(BlockAndTintGetter level, Fluid fluid, BlockPos pos, BlockState blockState, FluidState fluidState) {
 | |
| 		if (fluid.isSame(fluidState.getType())) {
 | |
| 			BlockState blockState2 = level.getBlockState(pos.above());
 | |
| 			return fluid.isSame(blockState2.getFluidState().getType()) ? 1.0F : fluidState.getOwnHeight();
 | |
| 		} else {
 | |
| 			return !blockState.isSolid() ? 0.0F : -1.0F;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void vertex(VertexConsumer buffer, float x, float y, float z, float red, float green, float blue, float u, float v, int packedLight) {
 | |
| 		buffer.addVertex(x, y, z).setColor(red, green, blue, 1.0F).setUv(u, v).setLight(packedLight).setNormal(0.0F, 1.0F, 0.0F);
 | |
| 	}
 | |
| 
 | |
| 	private int getLightColor(BlockAndTintGetter level, BlockPos pos) {
 | |
| 		int i = LevelRenderer.getLightColor(level, pos);
 | |
| 		int j = LevelRenderer.getLightColor(level, pos.above());
 | |
| 		int k = i & 0xFF;
 | |
| 		int l = j & 0xFF;
 | |
| 		int m = i >> 16 & 0xFF;
 | |
| 		int n = j >> 16 & 0xFF;
 | |
| 		return (k > l ? k : l) | (m > n ? m : n) << 16;
 | |
| 	}
 | |
| }
 |