366 lines
12 KiB
Java
366 lines
12 KiB
Java
package net.minecraft.client.renderer;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
import com.google.gson.JsonArray;
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonObject;
|
|
import com.google.gson.JsonSyntaxException;
|
|
import com.mojang.blaze3d.pipeline.RenderTarget;
|
|
import com.mojang.blaze3d.pipeline.TextureTarget;
|
|
import com.mojang.blaze3d.shaders.Uniform;
|
|
import com.mojang.blaze3d.systems.RenderSystem;
|
|
import java.io.IOException;
|
|
import java.io.Reader;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
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.server.ChainedJsonException;
|
|
import net.minecraft.server.packs.resources.Resource;
|
|
import net.minecraft.server.packs.resources.ResourceProvider;
|
|
import net.minecraft.util.GsonHelper;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.joml.Matrix4f;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class PostChain implements AutoCloseable {
|
|
private static final String MAIN_RENDER_TARGET = "minecraft:main";
|
|
private final RenderTarget screenTarget;
|
|
private final ResourceProvider resourceProvider;
|
|
private final String name;
|
|
private final List<PostPass> passes = Lists.<PostPass>newArrayList();
|
|
private final Map<String, RenderTarget> customRenderTargets = Maps.<String, RenderTarget>newHashMap();
|
|
private final List<RenderTarget> fullSizedTargets = Lists.<RenderTarget>newArrayList();
|
|
private Matrix4f shaderOrthoMatrix;
|
|
private int screenWidth;
|
|
private int screenHeight;
|
|
private float time;
|
|
private float lastStamp;
|
|
|
|
public PostChain(TextureManager textureManager, ResourceProvider resourceProvider, RenderTarget screenTarget, ResourceLocation resourceLocation) throws IOException, JsonSyntaxException {
|
|
this.resourceProvider = resourceProvider;
|
|
this.screenTarget = screenTarget;
|
|
this.time = 0.0F;
|
|
this.lastStamp = 0.0F;
|
|
this.screenWidth = screenTarget.viewWidth;
|
|
this.screenHeight = screenTarget.viewHeight;
|
|
this.name = resourceLocation.toString();
|
|
this.updateOrthoMatrix();
|
|
this.load(textureManager, resourceLocation);
|
|
}
|
|
|
|
private void load(TextureManager textureManager, ResourceLocation resourceLocation) throws IOException, JsonSyntaxException {
|
|
Resource resource = this.resourceProvider.getResourceOrThrow(resourceLocation);
|
|
|
|
try {
|
|
Reader reader = resource.openAsReader();
|
|
|
|
try {
|
|
JsonObject jsonObject = GsonHelper.parse(reader);
|
|
if (GsonHelper.isArrayNode(jsonObject, "targets")) {
|
|
JsonArray jsonArray = jsonObject.getAsJsonArray("targets");
|
|
int i = 0;
|
|
|
|
for (JsonElement jsonElement : jsonArray) {
|
|
try {
|
|
this.parseTargetNode(jsonElement);
|
|
} catch (Exception var14) {
|
|
ChainedJsonException chainedJsonException = ChainedJsonException.forException(var14);
|
|
chainedJsonException.prependJsonKey("targets[" + i + "]");
|
|
throw chainedJsonException;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (GsonHelper.isArrayNode(jsonObject, "passes")) {
|
|
JsonArray jsonArray = jsonObject.getAsJsonArray("passes");
|
|
int i = 0;
|
|
|
|
for (JsonElement jsonElement : jsonArray) {
|
|
try {
|
|
this.parsePassNode(textureManager, jsonElement);
|
|
} catch (Exception var13) {
|
|
ChainedJsonException chainedJsonException = ChainedJsonException.forException(var13);
|
|
chainedJsonException.prependJsonKey("passes[" + i + "]");
|
|
throw chainedJsonException;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
} catch (Throwable var15) {
|
|
if (reader != null) {
|
|
try {
|
|
reader.close();
|
|
} catch (Throwable var12) {
|
|
var15.addSuppressed(var12);
|
|
}
|
|
}
|
|
|
|
throw var15;
|
|
}
|
|
|
|
if (reader != null) {
|
|
reader.close();
|
|
}
|
|
} catch (Exception var16) {
|
|
ChainedJsonException chainedJsonException2 = ChainedJsonException.forException(var16);
|
|
chainedJsonException2.setFilenameAndFlush(resourceLocation.getPath() + " (" + resource.sourcePackId() + ")");
|
|
throw chainedJsonException2;
|
|
}
|
|
}
|
|
|
|
private void parseTargetNode(JsonElement json) throws ChainedJsonException {
|
|
if (GsonHelper.isStringValue(json)) {
|
|
this.addTempTarget(json.getAsString(), this.screenWidth, this.screenHeight);
|
|
} else {
|
|
JsonObject jsonObject = GsonHelper.convertToJsonObject(json, "target");
|
|
String string = GsonHelper.getAsString(jsonObject, "name");
|
|
int i = GsonHelper.getAsInt(jsonObject, "width", this.screenWidth);
|
|
int j = GsonHelper.getAsInt(jsonObject, "height", this.screenHeight);
|
|
if (this.customRenderTargets.containsKey(string)) {
|
|
throw new ChainedJsonException(string + " is already defined");
|
|
}
|
|
|
|
this.addTempTarget(string, i, j);
|
|
}
|
|
}
|
|
|
|
private void parsePassNode(TextureManager textureManager, JsonElement json) throws IOException {
|
|
JsonObject jsonObject = GsonHelper.convertToJsonObject(json, "pass");
|
|
String string = GsonHelper.getAsString(jsonObject, "name");
|
|
String string2 = GsonHelper.getAsString(jsonObject, "intarget");
|
|
String string3 = GsonHelper.getAsString(jsonObject, "outtarget");
|
|
RenderTarget renderTarget = this.getRenderTarget(string2);
|
|
RenderTarget renderTarget2 = this.getRenderTarget(string3);
|
|
boolean bl = GsonHelper.getAsBoolean(jsonObject, "use_linear_filter", false);
|
|
if (renderTarget == null) {
|
|
throw new ChainedJsonException("Input target '" + string2 + "' does not exist");
|
|
} else if (renderTarget2 == null) {
|
|
throw new ChainedJsonException("Output target '" + string3 + "' does not exist");
|
|
} else {
|
|
PostPass postPass = this.addPass(string, renderTarget, renderTarget2, bl);
|
|
JsonArray jsonArray = GsonHelper.getAsJsonArray(jsonObject, "auxtargets", null);
|
|
if (jsonArray != null) {
|
|
int i = 0;
|
|
|
|
for (JsonElement jsonElement : jsonArray) {
|
|
try {
|
|
JsonObject jsonObject2 = GsonHelper.convertToJsonObject(jsonElement, "auxtarget");
|
|
String string4 = GsonHelper.getAsString(jsonObject2, "name");
|
|
String string5 = GsonHelper.getAsString(jsonObject2, "id");
|
|
boolean bl2;
|
|
String string6;
|
|
if (string5.endsWith(":depth")) {
|
|
bl2 = true;
|
|
string6 = string5.substring(0, string5.lastIndexOf(58));
|
|
} else {
|
|
bl2 = false;
|
|
string6 = string5;
|
|
}
|
|
|
|
RenderTarget renderTarget3 = this.getRenderTarget(string6);
|
|
if (renderTarget3 == null) {
|
|
if (bl2) {
|
|
throw new ChainedJsonException("Render target '" + string6 + "' can't be used as depth buffer");
|
|
}
|
|
|
|
ResourceLocation resourceLocation = ResourceLocation.withDefaultNamespace("textures/effect/" + string6 + ".png");
|
|
this.resourceProvider
|
|
.getResource(resourceLocation)
|
|
.orElseThrow(() -> new ChainedJsonException("Render target or texture '" + string6 + "' does not exist"));
|
|
RenderSystem.setShaderTexture(0, resourceLocation);
|
|
textureManager.bindForSetup(resourceLocation);
|
|
AbstractTexture abstractTexture = textureManager.getTexture(resourceLocation);
|
|
int j = GsonHelper.getAsInt(jsonObject2, "width");
|
|
int k = GsonHelper.getAsInt(jsonObject2, "height");
|
|
boolean bl3 = GsonHelper.getAsBoolean(jsonObject2, "bilinear");
|
|
if (bl3) {
|
|
RenderSystem.texParameter(3553, 10241, 9729);
|
|
RenderSystem.texParameter(3553, 10240, 9729);
|
|
} else {
|
|
RenderSystem.texParameter(3553, 10241, 9728);
|
|
RenderSystem.texParameter(3553, 10240, 9728);
|
|
}
|
|
|
|
postPass.addAuxAsset(string4, abstractTexture::getId, j, k);
|
|
} else if (bl2) {
|
|
postPass.addAuxAsset(string4, renderTarget3::getDepthTextureId, renderTarget3.width, renderTarget3.height);
|
|
} else {
|
|
postPass.addAuxAsset(string4, renderTarget3::getColorTextureId, renderTarget3.width, renderTarget3.height);
|
|
}
|
|
} catch (Exception var27) {
|
|
ChainedJsonException chainedJsonException = ChainedJsonException.forException(var27);
|
|
chainedJsonException.prependJsonKey("auxtargets[" + i + "]");
|
|
throw chainedJsonException;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
JsonArray jsonArray2 = GsonHelper.getAsJsonArray(jsonObject, "uniforms", null);
|
|
if (jsonArray2 != null) {
|
|
int l = 0;
|
|
|
|
for (JsonElement jsonElement2 : jsonArray2) {
|
|
try {
|
|
this.parseUniformNode(jsonElement2);
|
|
} catch (Exception var26) {
|
|
ChainedJsonException chainedJsonException2 = ChainedJsonException.forException(var26);
|
|
chainedJsonException2.prependJsonKey("uniforms[" + l + "]");
|
|
throw chainedJsonException2;
|
|
}
|
|
|
|
l++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void parseUniformNode(JsonElement json) throws ChainedJsonException {
|
|
JsonObject jsonObject = GsonHelper.convertToJsonObject(json, "uniform");
|
|
String string = GsonHelper.getAsString(jsonObject, "name");
|
|
Uniform uniform = ((PostPass)this.passes.get(this.passes.size() - 1)).getEffect().getUniform(string);
|
|
if (uniform == null) {
|
|
throw new ChainedJsonException("Uniform '" + string + "' does not exist");
|
|
} else {
|
|
float[] fs = new float[4];
|
|
int i = 0;
|
|
|
|
for (JsonElement jsonElement : GsonHelper.getAsJsonArray(jsonObject, "values")) {
|
|
try {
|
|
fs[i] = GsonHelper.convertToFloat(jsonElement, "value");
|
|
} catch (Exception var12) {
|
|
ChainedJsonException chainedJsonException = ChainedJsonException.forException(var12);
|
|
chainedJsonException.prependJsonKey("values[" + i + "]");
|
|
throw chainedJsonException;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
switch (i) {
|
|
case 0:
|
|
default:
|
|
break;
|
|
case 1:
|
|
uniform.set(fs[0]);
|
|
break;
|
|
case 2:
|
|
uniform.set(fs[0], fs[1]);
|
|
break;
|
|
case 3:
|
|
uniform.set(fs[0], fs[1], fs[2]);
|
|
break;
|
|
case 4:
|
|
uniform.set(fs[0], fs[1], fs[2], fs[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public RenderTarget getTempTarget(String attributeName) {
|
|
return (RenderTarget)this.customRenderTargets.get(attributeName);
|
|
}
|
|
|
|
public void addTempTarget(String name, int width, int height) {
|
|
RenderTarget renderTarget = new TextureTarget(width, height, true, Minecraft.ON_OSX);
|
|
renderTarget.setClearColor(0.0F, 0.0F, 0.0F, 0.0F);
|
|
this.customRenderTargets.put(name, renderTarget);
|
|
if (width == this.screenWidth && height == this.screenHeight) {
|
|
this.fullSizedTargets.add(renderTarget);
|
|
}
|
|
}
|
|
|
|
public void close() {
|
|
for (RenderTarget renderTarget : this.customRenderTargets.values()) {
|
|
renderTarget.destroyBuffers();
|
|
}
|
|
|
|
for (PostPass postPass : this.passes) {
|
|
postPass.close();
|
|
}
|
|
|
|
this.passes.clear();
|
|
}
|
|
|
|
public PostPass addPass(String name, RenderTarget inTarget, RenderTarget outTarget, boolean useLinearFilter) throws IOException {
|
|
PostPass postPass = new PostPass(this.resourceProvider, name, inTarget, outTarget, useLinearFilter);
|
|
this.passes.add(this.passes.size(), postPass);
|
|
return postPass;
|
|
}
|
|
|
|
private void updateOrthoMatrix() {
|
|
this.shaderOrthoMatrix = new Matrix4f().setOrtho(0.0F, this.screenTarget.width, 0.0F, this.screenTarget.height, 0.1F, 1000.0F);
|
|
}
|
|
|
|
public void resize(int width, int height) {
|
|
this.screenWidth = this.screenTarget.width;
|
|
this.screenHeight = this.screenTarget.height;
|
|
this.updateOrthoMatrix();
|
|
|
|
for (PostPass postPass : this.passes) {
|
|
postPass.setOrthoMatrix(this.shaderOrthoMatrix);
|
|
}
|
|
|
|
for (RenderTarget renderTarget : this.fullSizedTargets) {
|
|
renderTarget.resize(width, height, Minecraft.ON_OSX);
|
|
}
|
|
}
|
|
|
|
private void setFilterMode(int filterMode) {
|
|
this.screenTarget.setFilterMode(filterMode);
|
|
|
|
for (RenderTarget renderTarget : this.customRenderTargets.values()) {
|
|
renderTarget.setFilterMode(filterMode);
|
|
}
|
|
}
|
|
|
|
public void process(float partialTicks) {
|
|
this.time += partialTicks;
|
|
|
|
while (this.time > 20.0F) {
|
|
this.time -= 20.0F;
|
|
}
|
|
|
|
int i = 9728;
|
|
|
|
for (PostPass postPass : this.passes) {
|
|
int j = postPass.getFilterMode();
|
|
if (i != j) {
|
|
this.setFilterMode(j);
|
|
i = j;
|
|
}
|
|
|
|
postPass.process(this.time / 20.0F);
|
|
}
|
|
|
|
this.setFilterMode(9728);
|
|
}
|
|
|
|
public void setUniform(String name, float backgroundBlurriness) {
|
|
for (PostPass postPass : this.passes) {
|
|
postPass.getEffect().safeGetUniform(name).set(backgroundBlurriness);
|
|
}
|
|
}
|
|
|
|
public final String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
@Nullable
|
|
private RenderTarget getRenderTarget(@Nullable String target) {
|
|
if (target == null) {
|
|
return null;
|
|
} else {
|
|
return target.equals("minecraft:main") ? this.screenTarget : (RenderTarget)this.customRenderTargets.get(target);
|
|
}
|
|
}
|
|
}
|