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 samplers = new ArrayList(); private final Object2IntMap samplerTextures = new Object2IntArrayMap<>(); private final IntList samplerLocations = new IntArrayList(); private final List uniforms = new ArrayList(); private final Map uniformsByName = new HashMap(); private final Map 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 uniforms, List 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; } }