274 lines
9.3 KiB
Java
274 lines
9.3 KiB
Java
package net.minecraft.client.renderer;
|
|
|
|
import com.mojang.blaze3d.platform.GlStateManager;
|
|
import com.mojang.blaze3d.platform.Window;
|
|
import com.mojang.blaze3d.shaders.AbstractUniform;
|
|
import com.mojang.blaze3d.shaders.CompiledShader;
|
|
import com.mojang.blaze3d.systems.RenderSystem;
|
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|
import it.unimi.dsi.fastutil.ints.IntList;
|
|
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.renderer.ShaderProgramConfig.Sampler;
|
|
import net.minecraft.client.renderer.ShaderProgramConfig.Uniform;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.jetbrains.annotations.VisibleForTesting;
|
|
import org.joml.Matrix4f;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class CompiledShaderProgram implements AutoCloseable {
|
|
private static final AbstractUniform DUMMY_UNIFORM = new AbstractUniform();
|
|
private static final int NO_SAMPLER_TEXTURE = -1;
|
|
private final List<Sampler> samplers = new ArrayList();
|
|
private final Object2IntMap<String> samplerTextures = new Object2IntArrayMap<>();
|
|
private final IntList samplerLocations = new IntArrayList();
|
|
private final List<com.mojang.blaze3d.shaders.Uniform> uniforms = new ArrayList();
|
|
private final Map<String, com.mojang.blaze3d.shaders.Uniform> uniformsByName = new HashMap();
|
|
private final Map<String, Uniform> uniformConfigs = new HashMap();
|
|
private final int programId;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform MODEL_VIEW_MATRIX;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform PROJECTION_MATRIX;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform TEXTURE_MATRIX;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform SCREEN_SIZE;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform COLOR_MODULATOR;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform LIGHT0_DIRECTION;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform LIGHT1_DIRECTION;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform GLINT_ALPHA;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform FOG_START;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform FOG_END;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform FOG_COLOR;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform FOG_SHAPE;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform LINE_WIDTH;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform GAME_TIME;
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform MODEL_OFFSET;
|
|
|
|
private CompiledShaderProgram(int programId) {
|
|
this.programId = programId;
|
|
this.samplerTextures.defaultReturnValue(-1);
|
|
}
|
|
|
|
public static CompiledShaderProgram link(CompiledShader vertexShader, CompiledShader fragmentShader, VertexFormat vertexFormat) throws ShaderManager.CompilationException {
|
|
int i = GlStateManager.glCreateProgram();
|
|
if (i <= 0) {
|
|
throw new ShaderManager.CompilationException("Could not create shader program (returned program ID " + i + ")");
|
|
} else {
|
|
vertexFormat.bindAttributes(i);
|
|
GlStateManager.glAttachShader(i, vertexShader.getShaderId());
|
|
GlStateManager.glAttachShader(i, fragmentShader.getShaderId());
|
|
GlStateManager.glLinkProgram(i);
|
|
int j = GlStateManager.glGetProgrami(i, 35714);
|
|
if (j == 0) {
|
|
String string = GlStateManager.glGetProgramInfoLog(i, 32768);
|
|
throw new ShaderManager.CompilationException(
|
|
"Error encountered when linking program containing VS " + vertexShader.getId() + " and FS " + fragmentShader.getId() + ". Log output: " + string
|
|
);
|
|
} else {
|
|
return new CompiledShaderProgram(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setupUniforms(List<Uniform> uniforms, List<Sampler> samplers) {
|
|
RenderSystem.assertOnRenderThread();
|
|
|
|
for (Uniform uniform : uniforms) {
|
|
String string = uniform.name();
|
|
int i = com.mojang.blaze3d.shaders.Uniform.glGetUniformLocation(this.programId, string);
|
|
if (i != -1) {
|
|
com.mojang.blaze3d.shaders.Uniform uniform2 = this.parseUniformNode(uniform);
|
|
uniform2.setLocation(i);
|
|
this.uniforms.add(uniform2);
|
|
this.uniformsByName.put(string, uniform2);
|
|
this.uniformConfigs.put(string, uniform);
|
|
}
|
|
}
|
|
|
|
for (Sampler sampler : samplers) {
|
|
int j = com.mojang.blaze3d.shaders.Uniform.glGetUniformLocation(this.programId, sampler.name());
|
|
if (j != -1) {
|
|
this.samplers.add(sampler);
|
|
this.samplerLocations.add(j);
|
|
}
|
|
}
|
|
|
|
this.MODEL_VIEW_MATRIX = this.getUniform("ModelViewMat");
|
|
this.PROJECTION_MATRIX = this.getUniform("ProjMat");
|
|
this.TEXTURE_MATRIX = this.getUniform("TextureMat");
|
|
this.SCREEN_SIZE = this.getUniform("ScreenSize");
|
|
this.COLOR_MODULATOR = this.getUniform("ColorModulator");
|
|
this.LIGHT0_DIRECTION = this.getUniform("Light0_Direction");
|
|
this.LIGHT1_DIRECTION = this.getUniform("Light1_Direction");
|
|
this.GLINT_ALPHA = this.getUniform("GlintAlpha");
|
|
this.FOG_START = this.getUniform("FogStart");
|
|
this.FOG_END = this.getUniform("FogEnd");
|
|
this.FOG_COLOR = this.getUniform("FogColor");
|
|
this.FOG_SHAPE = this.getUniform("FogShape");
|
|
this.LINE_WIDTH = this.getUniform("LineWidth");
|
|
this.GAME_TIME = this.getUniform("GameTime");
|
|
this.MODEL_OFFSET = this.getUniform("ModelOffset");
|
|
}
|
|
|
|
public void close() {
|
|
this.uniforms.forEach(com.mojang.blaze3d.shaders.Uniform::close);
|
|
GlStateManager.glDeleteProgram(this.programId);
|
|
}
|
|
|
|
public void clear() {
|
|
RenderSystem.assertOnRenderThread();
|
|
GlStateManager._glUseProgram(0);
|
|
int i = GlStateManager._getActiveTexture();
|
|
|
|
for (int j = 0; j < this.samplerLocations.size(); j++) {
|
|
Sampler sampler = (Sampler)this.samplers.get(j);
|
|
if (!this.samplerTextures.containsKey(sampler.name())) {
|
|
GlStateManager._activeTexture(33984 + j);
|
|
GlStateManager._bindTexture(0);
|
|
}
|
|
}
|
|
|
|
GlStateManager._activeTexture(i);
|
|
}
|
|
|
|
public void apply() {
|
|
RenderSystem.assertOnRenderThread();
|
|
GlStateManager._glUseProgram(this.programId);
|
|
int i = GlStateManager._getActiveTexture();
|
|
|
|
for (int j = 0; j < this.samplerLocations.size(); j++) {
|
|
String string = ((Sampler)this.samplers.get(j)).name();
|
|
int k = this.samplerTextures.getInt(string);
|
|
if (k != -1) {
|
|
int l = this.samplerLocations.getInt(j);
|
|
com.mojang.blaze3d.shaders.Uniform.uploadInteger(l, j);
|
|
RenderSystem.activeTexture(33984 + j);
|
|
RenderSystem.bindTexture(k);
|
|
}
|
|
}
|
|
|
|
GlStateManager._activeTexture(i);
|
|
|
|
for (com.mojang.blaze3d.shaders.Uniform uniform : this.uniforms) {
|
|
uniform.upload();
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public com.mojang.blaze3d.shaders.Uniform getUniform(String name) {
|
|
RenderSystem.assertOnRenderThread();
|
|
return (com.mojang.blaze3d.shaders.Uniform)this.uniformsByName.get(name);
|
|
}
|
|
|
|
@Nullable
|
|
public Uniform getUniformConfig(String name) {
|
|
return (Uniform)this.uniformConfigs.get(name);
|
|
}
|
|
|
|
public AbstractUniform safeGetUniform(String name) {
|
|
com.mojang.blaze3d.shaders.Uniform uniform = this.getUniform(name);
|
|
return (AbstractUniform)(uniform == null ? DUMMY_UNIFORM : uniform);
|
|
}
|
|
|
|
public void bindSampler(String samplerName, int textureId) {
|
|
this.samplerTextures.put(samplerName, textureId);
|
|
}
|
|
|
|
private com.mojang.blaze3d.shaders.Uniform parseUniformNode(Uniform uniform) {
|
|
int i = com.mojang.blaze3d.shaders.Uniform.getTypeFromString(uniform.type());
|
|
int j = uniform.count();
|
|
int k = j > 1 && j <= 4 && i < 8 ? j - 1 : 0;
|
|
com.mojang.blaze3d.shaders.Uniform uniform2 = new com.mojang.blaze3d.shaders.Uniform(uniform.name(), i + k, j);
|
|
uniform2.setFromConfig(uniform);
|
|
return uniform2;
|
|
}
|
|
|
|
public void setDefaultUniforms(VertexFormat.Mode mode, Matrix4f frustumMatrix, Matrix4f projectionMatrix, Window window) {
|
|
for (int i = 0; i < 12; i++) {
|
|
int j = RenderSystem.getShaderTexture(i);
|
|
this.bindSampler("Sampler" + i, j);
|
|
}
|
|
|
|
if (this.MODEL_VIEW_MATRIX != null) {
|
|
this.MODEL_VIEW_MATRIX.set(frustumMatrix);
|
|
}
|
|
|
|
if (this.PROJECTION_MATRIX != null) {
|
|
this.PROJECTION_MATRIX.set(projectionMatrix);
|
|
}
|
|
|
|
if (this.COLOR_MODULATOR != null) {
|
|
this.COLOR_MODULATOR.set(RenderSystem.getShaderColor());
|
|
}
|
|
|
|
if (this.GLINT_ALPHA != null) {
|
|
this.GLINT_ALPHA.set(RenderSystem.getShaderGlintAlpha());
|
|
}
|
|
|
|
FogParameters fogParameters = RenderSystem.getShaderFog();
|
|
if (this.FOG_START != null) {
|
|
this.FOG_START.set(fogParameters.start());
|
|
}
|
|
|
|
if (this.FOG_END != null) {
|
|
this.FOG_END.set(fogParameters.end());
|
|
}
|
|
|
|
if (this.FOG_COLOR != null) {
|
|
this.FOG_COLOR.set(fogParameters.red(), fogParameters.green(), fogParameters.blue(), fogParameters.alpha());
|
|
}
|
|
|
|
if (this.FOG_SHAPE != null) {
|
|
this.FOG_SHAPE.set(fogParameters.shape().getIndex());
|
|
}
|
|
|
|
if (this.TEXTURE_MATRIX != null) {
|
|
this.TEXTURE_MATRIX.set(RenderSystem.getTextureMatrix());
|
|
}
|
|
|
|
if (this.GAME_TIME != null) {
|
|
this.GAME_TIME.set(RenderSystem.getShaderGameTime());
|
|
}
|
|
|
|
if (this.SCREEN_SIZE != null) {
|
|
this.SCREEN_SIZE.set((float)window.getWidth(), (float)window.getHeight());
|
|
}
|
|
|
|
if (this.LINE_WIDTH != null && (mode == VertexFormat.Mode.LINES || mode == VertexFormat.Mode.LINE_STRIP)) {
|
|
this.LINE_WIDTH.set(RenderSystem.getShaderLineWidth());
|
|
}
|
|
|
|
RenderSystem.setupShaderLights(this);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public void registerUniform(com.mojang.blaze3d.shaders.Uniform uniform) {
|
|
this.uniforms.add(uniform);
|
|
this.uniformsByName.put(uniform.getName(), uniform);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public int getProgramId() {
|
|
return this.programId;
|
|
}
|
|
}
|