package net.minecraft.client.renderer; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.google.common.collect.ImmutableList.Builder; import com.mojang.blaze3d.framegraph.FrameGraphBuilder; import com.mojang.blaze3d.pipeline.CompiledRenderPipeline; import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.resource.RenderTargetDescriptor; import com.mojang.blaze3d.resource.ResourceHandle; import com.mojang.blaze3d.shaders.UniformType; import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderSystem; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.Map.Entry; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.renderer.PostChain.TargetBundle.1; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; @Environment(EnvType.CLIENT) public class PostChain { public static final ResourceLocation MAIN_TARGET_ID = ResourceLocation.withDefaultNamespace("main"); private final List passes; private final Map internalTargets; private final Set externalTargets; private PostChain(List passes, Map internalTargets, Set externalTargets) { this.passes = passes; this.internalTargets = internalTargets; this.externalTargets = externalTargets; } public static PostChain load(PostChainConfig config, TextureManager textureManager, Set externalTargets, ResourceLocation name) throws ShaderManager.CompilationException { Stream stream = config.passes().stream().flatMap(PostChainConfig.Pass::referencedTargets); Set set = (Set)stream.filter(resourceLocation -> !config.internalTargets().containsKey(resourceLocation)) .collect(Collectors.toSet()); Set set2 = Sets.difference(set, externalTargets); if (!set2.isEmpty()) { throw new ShaderManager.CompilationException("Referenced external targets are not available in this context: " + set2); } else { Builder builder = ImmutableList.builder(); for (int i = 0; i < config.passes().size(); i++) { PostChainConfig.Pass pass = (PostChainConfig.Pass)config.passes().get(i); builder.add(createPass(textureManager, pass, name.withSuffix("/" + i))); } return new PostChain(builder.build(), config.internalTargets(), set); } } private static PostPass createPass(TextureManager textureManager, PostChainConfig.Pass pass, ResourceLocation location) throws ShaderManager.CompilationException { RenderPipeline.Builder builder = RenderPipeline.builder(RenderPipelines.POST_PROCESSING_SNIPPET) .withFragmentShader(pass.fragmentShaderId()) .withVertexShader(pass.vertexShaderId()) .withLocation(location); for (PostChainConfig.Input input : pass.inputs()) { builder.withSampler(input.samplerName() + "Sampler"); builder.withUniform(input.samplerName() + "Size", UniformType.VEC2); } for (PostChainConfig.Uniform uniform : pass.uniforms()) { builder.withUniform(uniform.name(), (UniformType)Objects.requireNonNull((UniformType)UniformType.CODEC.byName(uniform.type()))); } RenderPipeline renderPipeline = builder.build(); CompiledRenderPipeline compiledRenderPipeline = RenderSystem.getDevice().precompilePipeline(renderPipeline); for (PostChainConfig.Uniform uniform2 : pass.uniforms()) { String string = uniform2.name(); if (!compiledRenderPipeline.containsUniform(string)) { throw new ShaderManager.CompilationException("Uniform '" + string + "' does not exist for " + location); } } PostPass postPass = new PostPass(renderPipeline, pass.outputTarget(), pass.uniforms()); for (PostChainConfig.Input input2 : pass.inputs()) { switch (input2) { case PostChainConfig.TextureInput(String var39, ResourceLocation var40, int var41, int var42, boolean var43): AbstractTexture abstractTexture = textureManager.getTexture(var40.withPath((UnaryOperator)(string -> "textures/effect/" + string + ".png"))); abstractTexture.setFilter(var43, false); postPass.addInput(new PostPass.TextureInput(var39, abstractTexture, var41, var42)); break; case PostChainConfig.TargetInput(String var22, ResourceLocation var45, boolean var46, boolean var47): postPass.addInput(new PostPass.TargetInput(var22, var45, var46, var47)); break; default: throw new MatchException(null, null); } } return postPass; } public void addToFrame( FrameGraphBuilder frameGraphBuilder, int width, int height, PostChain.TargetBundle targetBundle, @Nullable Consumer uniformSetter ) { Matrix4f matrix4f = new Matrix4f().setOrtho(0.0F, width, 0.0F, height, 0.1F, 1000.0F); Map> map = new HashMap(this.internalTargets.size() + this.externalTargets.size()); for (ResourceLocation resourceLocation : this.externalTargets) { map.put(resourceLocation, targetBundle.getOrThrow(resourceLocation)); } for (Entry entry : this.internalTargets.entrySet()) { ResourceLocation resourceLocation2 = (ResourceLocation)entry.getKey(); RenderTargetDescriptor renderTargetDescriptor = switch ((PostChainConfig.InternalTarget)entry.getValue()) { case PostChainConfig.FixedSizedTarget(int var26, int var27) -> new RenderTargetDescriptor(var26, var27, true, 0); case PostChainConfig.FullScreenTarget var17 -> new RenderTargetDescriptor(width, height, true, 0); default -> throw new MatchException(null, null); }; map.put(resourceLocation2, frameGraphBuilder.createInternal(resourceLocation2.toString(), renderTargetDescriptor)); } for (PostPass postPass : this.passes) { postPass.addToFrame(frameGraphBuilder, map, matrix4f, uniformSetter); } for (ResourceLocation resourceLocation : this.externalTargets) { targetBundle.replace(resourceLocation, (ResourceHandle)map.get(resourceLocation)); } } @Deprecated public void process(RenderTarget renderTarget, GraphicsResourceAllocator allocator, @Nullable Consumer uniformSetter) { FrameGraphBuilder frameGraphBuilder = new FrameGraphBuilder(); PostChain.TargetBundle targetBundle = PostChain.TargetBundle.of(MAIN_TARGET_ID, frameGraphBuilder.importExternal("main", renderTarget)); this.addToFrame(frameGraphBuilder, renderTarget.width, renderTarget.height, targetBundle, uniformSetter); frameGraphBuilder.execute(allocator); } @Environment(EnvType.CLIENT) public interface TargetBundle { static PostChain.TargetBundle of(ResourceLocation id, ResourceHandle handle) { return new 1(handle, id); } void replace(ResourceLocation id, ResourceHandle handle); @Nullable ResourceHandle get(ResourceLocation id); default ResourceHandle getOrThrow(ResourceLocation id) { ResourceHandle resourceHandle = this.get(id); if (resourceHandle == null) { throw new IllegalArgumentException("Missing target with id " + id); } else { return resourceHandle; } } } }