186 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer;
 | |
| 
 | |
| import com.mojang.blaze3d.buffers.GpuBuffer;
 | |
| import com.mojang.blaze3d.buffers.GpuBufferSlice;
 | |
| import com.mojang.blaze3d.pipeline.RenderPipeline;
 | |
| import com.mojang.blaze3d.pipeline.RenderTarget;
 | |
| import com.mojang.blaze3d.systems.RenderPass;
 | |
| import com.mojang.blaze3d.systems.RenderSystem;
 | |
| import com.mojang.blaze3d.textures.GpuTextureView;
 | |
| 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.VertexFormat;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Collections;
 | |
| import java.util.OptionalDouble;
 | |
| import java.util.OptionalInt;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.Util;
 | |
| import net.minecraft.client.Minecraft;
 | |
| import net.minecraft.client.renderer.texture.AbstractTexture;
 | |
| import net.minecraft.client.renderer.texture.TextureManager;
 | |
| import net.minecraft.resources.ResourceLocation;
 | |
| import net.minecraft.util.ARGB;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.world.level.border.WorldBorder;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| import org.joml.Matrix4f;
 | |
| import org.joml.Vector3f;
 | |
| import org.joml.Vector4f;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class WorldBorderRenderer {
 | |
| 	public static final ResourceLocation FORCEFIELD_LOCATION = ResourceLocation.withDefaultNamespace("textures/misc/forcefield.png");
 | |
| 	private boolean needsRebuild = true;
 | |
| 	private double lastMinX;
 | |
| 	private double lastMinZ;
 | |
| 	private double lastBorderMinX;
 | |
| 	private double lastBorderMaxX;
 | |
| 	private double lastBorderMinZ;
 | |
| 	private double lastBorderMaxZ;
 | |
| 	private final GpuBuffer worldBorderBuffer = RenderSystem.getDevice()
 | |
| 		.createBuffer(() -> "World border vertex buffer", 40, 16 * DefaultVertexFormat.POSITION_TEX.getVertexSize());
 | |
| 	private final RenderSystem.AutoStorageIndexBuffer indices = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
 | |
| 
 | |
| 	private void rebuildWorldBorderBuffer(WorldBorder worldBorder, double renderDistance, double camZ, double camX, float farPlaneDepth, float vBottom, float vTop) {
 | |
| 		try (ByteBufferBuilder byteBufferBuilder = ByteBufferBuilder.exactlySized(DefaultVertexFormat.POSITION_TEX.getVertexSize() * 4 * 4)) {
 | |
| 			double d = worldBorder.getMinX();
 | |
| 			double e = worldBorder.getMaxX();
 | |
| 			double f = worldBorder.getMinZ();
 | |
| 			double g = worldBorder.getMaxZ();
 | |
| 			double h = Math.max(Mth.floor(camZ - renderDistance), f);
 | |
| 			double i = Math.min(Mth.ceil(camZ + renderDistance), g);
 | |
| 			float j = (Mth.floor(h) & 1) * 0.5F;
 | |
| 			float k = (float)(i - h) / 2.0F;
 | |
| 			double l = Math.max(Mth.floor(camX - renderDistance), d);
 | |
| 			double m = Math.min(Mth.ceil(camX + renderDistance), e);
 | |
| 			float n = (Mth.floor(l) & 1) * 0.5F;
 | |
| 			float o = (float)(m - l) / 2.0F;
 | |
| 			BufferBuilder bufferBuilder = new BufferBuilder(byteBufferBuilder, VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
 | |
| 			bufferBuilder.addVertex(0.0F, -farPlaneDepth, (float)(g - h)).setUv(n, vBottom);
 | |
| 			bufferBuilder.addVertex((float)(m - l), -farPlaneDepth, (float)(g - h)).setUv(o + n, vBottom);
 | |
| 			bufferBuilder.addVertex((float)(m - l), farPlaneDepth, (float)(g - h)).setUv(o + n, vTop);
 | |
| 			bufferBuilder.addVertex(0.0F, farPlaneDepth, (float)(g - h)).setUv(n, vTop);
 | |
| 			bufferBuilder.addVertex(0.0F, -farPlaneDepth, 0.0F).setUv(j, vBottom);
 | |
| 			bufferBuilder.addVertex(0.0F, -farPlaneDepth, (float)(i - h)).setUv(k + j, vBottom);
 | |
| 			bufferBuilder.addVertex(0.0F, farPlaneDepth, (float)(i - h)).setUv(k + j, vTop);
 | |
| 			bufferBuilder.addVertex(0.0F, farPlaneDepth, 0.0F).setUv(j, vTop);
 | |
| 			bufferBuilder.addVertex((float)(m - l), -farPlaneDepth, 0.0F).setUv(n, vBottom);
 | |
| 			bufferBuilder.addVertex(0.0F, -farPlaneDepth, 0.0F).setUv(o + n, vBottom);
 | |
| 			bufferBuilder.addVertex(0.0F, farPlaneDepth, 0.0F).setUv(o + n, vTop);
 | |
| 			bufferBuilder.addVertex((float)(m - l), farPlaneDepth, 0.0F).setUv(n, vTop);
 | |
| 			bufferBuilder.addVertex((float)(e - l), -farPlaneDepth, (float)(i - h)).setUv(j, vBottom);
 | |
| 			bufferBuilder.addVertex((float)(e - l), -farPlaneDepth, 0.0F).setUv(k + j, vBottom);
 | |
| 			bufferBuilder.addVertex((float)(e - l), farPlaneDepth, 0.0F).setUv(k + j, vTop);
 | |
| 			bufferBuilder.addVertex((float)(e - l), farPlaneDepth, (float)(i - h)).setUv(j, vTop);
 | |
| 
 | |
| 			try (MeshData meshData = bufferBuilder.buildOrThrow()) {
 | |
| 				RenderSystem.getDevice().createCommandEncoder().writeToBuffer(this.worldBorderBuffer.slice(), meshData.vertexBuffer());
 | |
| 			}
 | |
| 
 | |
| 			this.lastBorderMinX = d;
 | |
| 			this.lastBorderMaxX = e;
 | |
| 			this.lastBorderMinZ = f;
 | |
| 			this.lastBorderMaxZ = g;
 | |
| 			this.lastMinX = l;
 | |
| 			this.lastMinZ = h;
 | |
| 			this.needsRebuild = false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void render(WorldBorder worldBorder, Vec3 cameraPosition, double renderDistance, double farPlaneDepth) {
 | |
| 		double d = worldBorder.getMinX();
 | |
| 		double e = worldBorder.getMaxX();
 | |
| 		double f = worldBorder.getMinZ();
 | |
| 		double g = worldBorder.getMaxZ();
 | |
| 		if ((
 | |
| 				!(cameraPosition.x < e - renderDistance)
 | |
| 					|| !(cameraPosition.x > d + renderDistance)
 | |
| 					|| !(cameraPosition.z < g - renderDistance)
 | |
| 					|| !(cameraPosition.z > f + renderDistance)
 | |
| 			)
 | |
| 			&& !(cameraPosition.x < d - renderDistance)
 | |
| 			&& !(cameraPosition.x > e + renderDistance)
 | |
| 			&& !(cameraPosition.z < f - renderDistance)
 | |
| 			&& !(cameraPosition.z > g + renderDistance)) {
 | |
| 			double h = 1.0 - worldBorder.getDistanceToBorder(cameraPosition.x, cameraPosition.z) / renderDistance;
 | |
| 			h = Math.pow(h, 4.0);
 | |
| 			h = Mth.clamp(h, 0.0, 1.0);
 | |
| 			double i = cameraPosition.x;
 | |
| 			double j = cameraPosition.z;
 | |
| 			float k = (float)farPlaneDepth;
 | |
| 			int l = worldBorder.getStatus().getColor();
 | |
| 			float m = ARGB.red(l) / 255.0F;
 | |
| 			float n = ARGB.green(l) / 255.0F;
 | |
| 			float o = ARGB.blue(l) / 255.0F;
 | |
| 			float p = (float)(Util.getMillis() % 3000L) / 3000.0F;
 | |
| 			float q = (float)(-Mth.frac(cameraPosition.y * 0.5));
 | |
| 			float r = q + k;
 | |
| 			if (this.shouldRebuildWorldBorderBuffer(worldBorder)) {
 | |
| 				this.rebuildWorldBorderBuffer(worldBorder, renderDistance, j, i, k, r, q);
 | |
| 			}
 | |
| 
 | |
| 			TextureManager textureManager = Minecraft.getInstance().getTextureManager();
 | |
| 			AbstractTexture abstractTexture = textureManager.getTexture(FORCEFIELD_LOCATION);
 | |
| 			abstractTexture.setUseMipmaps(false);
 | |
| 			RenderPipeline renderPipeline = RenderPipelines.WORLD_BORDER;
 | |
| 			RenderTarget renderTarget = Minecraft.getInstance().getMainRenderTarget();
 | |
| 			RenderTarget renderTarget2 = Minecraft.getInstance().levelRenderer.getWeatherTarget();
 | |
| 			GpuTextureView gpuTextureView;
 | |
| 			GpuTextureView gpuTextureView2;
 | |
| 			if (renderTarget2 != null) {
 | |
| 				gpuTextureView = renderTarget2.getColorTextureView();
 | |
| 				gpuTextureView2 = renderTarget2.getDepthTextureView();
 | |
| 			} else {
 | |
| 				gpuTextureView = renderTarget.getColorTextureView();
 | |
| 				gpuTextureView2 = renderTarget.getDepthTextureView();
 | |
| 			}
 | |
| 
 | |
| 			GpuBuffer gpuBuffer = this.indices.getBuffer(6);
 | |
| 			GpuBufferSlice gpuBufferSlice = RenderSystem.getDynamicUniforms()
 | |
| 				.writeTransform(
 | |
| 					RenderSystem.getModelViewMatrix(),
 | |
| 					new Vector4f(m, n, o, (float)h),
 | |
| 					new Vector3f((float)(this.lastMinX - i), (float)(-cameraPosition.y), (float)(this.lastMinZ - j)),
 | |
| 					new Matrix4f().translation(p, p, 0.0F),
 | |
| 					0.0F
 | |
| 				);
 | |
| 
 | |
| 			try (RenderPass renderPass = RenderSystem.getDevice()
 | |
| 					.createCommandEncoder()
 | |
| 					.createRenderPass(() -> "World border", gpuTextureView, OptionalInt.empty(), gpuTextureView2, OptionalDouble.empty())) {
 | |
| 				renderPass.setPipeline(renderPipeline);
 | |
| 				RenderSystem.bindDefaultUniforms(renderPass);
 | |
| 				renderPass.setUniform("DynamicTransforms", gpuBufferSlice);
 | |
| 				renderPass.setIndexBuffer(gpuBuffer, this.indices.type());
 | |
| 				renderPass.bindSampler("Sampler0", abstractTexture.getTextureView());
 | |
| 				renderPass.setVertexBuffer(0, this.worldBorderBuffer);
 | |
| 				ArrayList<RenderPass.Draw<WorldBorderRenderer>> arrayList = new ArrayList();
 | |
| 
 | |
| 				for (WorldBorder.DistancePerDirection distancePerDirection : worldBorder.closestBorder(i, j)) {
 | |
| 					if (distancePerDirection.distance() < renderDistance) {
 | |
| 						int s = distancePerDirection.direction().get2DDataValue();
 | |
| 						arrayList.add(new RenderPass.Draw(0, this.worldBorderBuffer, gpuBuffer, this.indices.type(), 6 * s, 6));
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				renderPass.drawMultipleIndexed(arrayList, null, null, Collections.emptyList(), this);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void invalidate() {
 | |
| 		this.needsRebuild = true;
 | |
| 	}
 | |
| 
 | |
| 	private boolean shouldRebuildWorldBorderBuffer(WorldBorder worldBorder) {
 | |
| 		return this.needsRebuild
 | |
| 			|| worldBorder.getMinX() != this.lastBorderMinX
 | |
| 			|| worldBorder.getMinZ() != this.lastBorderMinZ
 | |
| 			|| worldBorder.getMaxX() != this.lastBorderMaxX
 | |
| 			|| worldBorder.getMaxZ() != this.lastBorderMaxZ;
 | |
| 	}
 | |
| }
 |