182 lines
8.3 KiB
Java
182 lines
8.3 KiB
Java
package net.minecraft.client.renderer;
|
|
|
|
import com.mojang.blaze3d.buffers.BufferType;
|
|
import com.mojang.blaze3d.buffers.BufferUsage;
|
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
|
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.GpuTexture;
|
|
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.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.util.TriState;
|
|
import net.minecraft.world.level.border.WorldBorder;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.joml.Matrix4f;
|
|
|
|
@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", BufferType.VERTICES, BufferUsage.DYNAMIC_WRITE, 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 = new ByteBufferBuilder(DefaultVertexFormat.POSITION_TEX.getVertexSize() * 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, meshData.vertexBuffer(), 0);
|
|
}
|
|
|
|
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;
|
|
RenderSystem.setShaderColor(m, n, o, (float)h);
|
|
float p = (float)(Util.getMillis() % 3000L) / 3000.0F;
|
|
RenderSystem.setTextureMatrix(new Matrix4f().translation(p, p, 0.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);
|
|
}
|
|
|
|
RenderSystem.setModelOffset((float)(this.lastMinX - i), (float)(-cameraPosition.y), (float)(this.lastMinZ - j));
|
|
TextureManager textureManager = Minecraft.getInstance().getTextureManager();
|
|
AbstractTexture abstractTexture = textureManager.getTexture(FORCEFIELD_LOCATION);
|
|
abstractTexture.setFilter(TriState.FALSE, false);
|
|
RenderPipeline renderPipeline = RenderPipelines.WORLD_BORDER;
|
|
RenderTarget renderTarget = Minecraft.getInstance().getMainRenderTarget();
|
|
RenderTarget renderTarget2 = Minecraft.getInstance().levelRenderer.getWeatherTarget();
|
|
GpuTexture gpuTexture;
|
|
GpuTexture gpuTexture2;
|
|
if (renderTarget2 != null) {
|
|
gpuTexture = renderTarget2.getColorTexture();
|
|
gpuTexture2 = renderTarget2.getDepthTexture();
|
|
} else {
|
|
gpuTexture = renderTarget.getColorTexture();
|
|
gpuTexture2 = renderTarget.getDepthTexture();
|
|
}
|
|
|
|
GpuBuffer gpuBuffer = this.indices.getBuffer(6);
|
|
|
|
try (RenderPass renderPass = RenderSystem.getDevice()
|
|
.createCommandEncoder()
|
|
.createRenderPass(gpuTexture, OptionalInt.empty(), gpuTexture2, OptionalDouble.empty())) {
|
|
renderPass.setPipeline(renderPipeline);
|
|
renderPass.setIndexBuffer(gpuBuffer, this.indices.type());
|
|
renderPass.bindSampler("Sampler0", abstractTexture.getTexture());
|
|
renderPass.setVertexBuffer(0, this.worldBorderBuffer);
|
|
ArrayList<RenderPass.Draw> 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);
|
|
}
|
|
|
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
|
RenderSystem.resetTextureMatrix();
|
|
RenderSystem.resetModelOffset();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|