Files
Angelica/src/main/java/net/coderbot/iris/compat/dh/IrisLodRenderProgram.java
T

223 lines
9.5 KiB
Java

package net.coderbot.iris.compat.dh;
import com.google.common.primitives.Ints;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import net.coderbot.iris.gl.blending.BufferBlendOverride;
import net.coderbot.iris.gl.program.ProgramImages;
import net.coderbot.iris.gl.program.ProgramSamplers;
import net.coderbot.iris.gl.program.ProgramUniforms;
import net.coderbot.iris.gl.shader.GlShader;
import net.coderbot.iris.gl.shader.ShaderType;
import net.coderbot.iris.gl.state.FogMode;
import net.coderbot.iris.gl.texture.TextureType;
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
import net.coderbot.iris.pipeline.transform.PatchShaderType;
import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.samplers.IrisSamplers;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CommonUniforms;
import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import org.joml.Matrix4fc;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL32;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class IrisLodRenderProgram {
// Uniforms
public final int modelOffsetUniform;
public final int worldYOffsetUniform;
public final int mircoOffsetUniform;
// Fog/Clip Uniforms
public final int clipDistanceUniform;
private final int id;
private final ProgramUniforms uniforms;
private final CustomUniforms customUniforms;
private final ProgramSamplers samplers;
private final ProgramImages images;
private final BlendModeOverride blend;
private final BufferBlendOverride[] bufferBlendOverrides;
// This will bind AbstractVertexAttribute
private IrisLodRenderProgram(String name, boolean isShadowPass, boolean translucent, BlendModeOverride override, BufferBlendOverride[] bufferBlendOverrides, String vertex, String tessControl, String tessEval, String geometry, String fragment, CustomUniforms customUniforms, DeferredWorldRenderingPipeline pipeline) {
id = GLStateManager.glCreateProgram();
GLStateManager.glBindAttribLocation(this.id, 0, "vPosition");
GLStateManager.glBindAttribLocation(this.id, 1, "iris_color");
GLStateManager.glBindAttribLocation(this.id, 2, "irisExtra");
this.bufferBlendOverrides = bufferBlendOverrides;
GlShader vert = new GlShader(ShaderType.VERTEX, name + ".vsh", vertex);
GLStateManager.glAttachShader(id, vert.getHandle());
GlShader tessCont = null;
if (tessControl != null) {
tessCont = new GlShader(ShaderType.TESSELATION_CONTROL, name + ".tcs", tessControl);
GLStateManager.glAttachShader(id, tessCont.getHandle());
}
GlShader tessE = null;
if (tessEval != null) {
tessE = new GlShader(ShaderType.TESSELATION_EVAL, name + ".tes", tessEval);
GLStateManager.glAttachShader(id, tessE.getHandle());
}
GlShader geom = null;
if (geometry != null) {
geom = new GlShader(ShaderType.GEOMETRY, name + ".gsh", geometry);
GLStateManager.glAttachShader(id, geom.getHandle());
}
GlShader frag = new GlShader(ShaderType.FRAGMENT, name + ".fsh", fragment);
GLStateManager.glAttachShader(id, frag.getHandle());
GLStateManager.glLinkProgram(this.id);
int status = GLStateManager.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
if (status != 1) {
String message = "Shader link error in Iris DH program! Details: " + GLStateManager.glGetProgramInfoLog(this.id, 9999);
this.free();
throw new RuntimeException(message);
} else {
GLStateManager.glUseProgram(this.id);
}
vert.destroy();
frag.destroy();
if (tessCont != null) tessCont.destroy();
if (tessE != null) tessE.destroy();
if (geom != null) geom.destroy();
blend = override;
ProgramUniforms.Builder uniformBuilder = ProgramUniforms.builder(name, id);
ProgramSamplers.Builder samplerBuilder = ProgramSamplers.builder(id, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_VERTEX);
customUniforms.assignTo(uniformBuilder);
BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniformBuilder);
ProgramImages.Builder builder = ProgramImages.builder(id);
pipeline.addGbufferOrShadowSamplers(samplerBuilder, builder,
isShadowPass ? pipeline::getFlippedBeforeShadow : () -> translucent ? pipeline.getFlippedAfterTranslucent() : pipeline.getFlippedAfterPrepare(),
isShadowPass, false, true, false);
customUniforms.mapholderToPass(uniformBuilder, this);
this.uniforms = uniformBuilder.buildUniforms();
this.customUniforms = customUniforms;
samplers = samplerBuilder.build();
images = builder.build();
modelOffsetUniform = tryGetUniformLocation2("modelOffset");
worldYOffsetUniform = tryGetUniformLocation2("worldYOffset");
mircoOffsetUniform = tryGetUniformLocation2("mircoOffset");
// Fog/Clip Uniforms
clipDistanceUniform = tryGetUniformLocation2("clipDistance");
}
public static IrisLodRenderProgram createProgram(String name, boolean isShadowPass, boolean translucent, ProgramSource source, CustomUniforms uniforms, DeferredWorldRenderingPipeline pipeline) {
Map<PatchShaderType, String> transformed = TransformPatcher.patchDHTerrain(
name,
source.getVertexSource().orElseThrow(RuntimeException::new),
source.getTessControlSource().orElse(null),
source.getTessEvalSource().orElse(null),
source.getGeometrySource().orElse(null),
source.getFragmentSource().orElseThrow(RuntimeException::new),
pipeline.getTextureMap());
String vertex = transformed.get(PatchShaderType.VERTEX);
String tessControl = transformed.get(PatchShaderType.TESS_CONTROL);
String tessEval = transformed.get(PatchShaderType.TESS_EVAL);
String geometry = transformed.get(PatchShaderType.GEOMETRY);
String fragment = transformed.get(PatchShaderType.FRAGMENT);
PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, tessControl, tessEval, fragment);
List<BufferBlendOverride> bufferOverrides = new ArrayList<>();
source.getDirectives().getBufferBlendOverrides().forEach(information -> {
int index = Ints.indexOf(source.getDirectives().getDrawBuffers(), information.getIndex());
if (index > -1) {
bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode()));
}
});
return new IrisLodRenderProgram(name, isShadowPass, translucent, source.getDirectives().getBlendModeOverride().orElse(null), bufferOverrides.toArray(BufferBlendOverride[]::new), vertex, tessControl, tessEval, geometry, fragment, uniforms, pipeline);
}
// Noise Uniforms
public int tryGetUniformLocation2(CharSequence name) {
return GLStateManager.glGetUniformLocation(this.id, name);
}
// Override ShaderProgram.bind()
public void bind() {
GLStateManager.glUseProgram(id);
if (blend != null) blend.apply();
for (BufferBlendOverride override : bufferBlendOverrides) {
override.apply();
}
}
public void unbind() {
GLStateManager.glUseProgram(0);
ProgramUniforms.clearActiveUniforms();
ProgramSamplers.clearActiveSamplers();
BlendModeOverride.restore();
}
public void free() {
GLStateManager.glDeleteProgram(id);
}
public void fillUniformData(Matrix4fc projection, Matrix4fc modelView, int worldYOffset, float partialTicks) {
GLStateManager.glUseProgram(id);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + IrisSamplers.LIGHTMAP_TEXTURE_UNIT);
DynamicTexture lightmapTexture = ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture();
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, lightmapTexture.getGlTextureId());
LodRendererEvents.pushDhMatrices(projection, modelView);
setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset
// setUniform(skyLightUniform, skyLight);
if (worldYOffsetUniform != -1) setUniform(worldYOffsetUniform, (float) worldYOffset);
// Fog/Clip Uniforms
float dhNearClipDistance = DhApi.Delayed.renderProxy.getNearClipPlaneDistanceInBlocks(partialTicks);
setUniform(clipDistanceUniform, dhNearClipDistance);
samplers.update();
uniforms.update();
customUniforms.push(this);
images.update();
}
private void setUniform(int index, float value) {
GLStateManager.glUniform1f(index, value);
}
public void setModelPos(DhApiVec3f modelPos) {
setUniform(modelOffsetUniform, modelPos);
}
private void setUniform(int index, DhApiVec3f pos) {
GLStateManager.glUniform3f(index, pos.x, pos.y, pos.z);
}
}