package com.mojang.blaze3d.pipeline; import com.mojang.blaze3d.DontObfuscate; import com.mojang.blaze3d.platform.DepthTestFunction; import com.mojang.blaze3d.platform.LogicOp; import com.mojang.blaze3d.platform.PolygonMode; import com.mojang.blaze3d.shaders.UniformType; import com.mojang.blaze3d.vertex.VertexFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Map.Entry; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.renderer.ShaderDefines; import net.minecraft.resources.ResourceLocation; @Environment(EnvType.CLIENT) @DontObfuscate public class RenderPipeline { private final ResourceLocation location; private final ResourceLocation vertexShader; private final ResourceLocation fragmentShader; private final ShaderDefines shaderDefines; private final List samplers; private final List uniforms; private final DepthTestFunction depthTestFunction; private final PolygonMode polygonMode; private final boolean cull; private final LogicOp colorLogic; private final Optional blendFunction; private final boolean writeColor; private final boolean writeAlpha; private final boolean writeDepth; private final VertexFormat vertexFormat; private final VertexFormat.Mode vertexFormatMode; private final float depthBiasScaleFactor; private final float depthBiasConstant; protected RenderPipeline( ResourceLocation resourceLocation, ResourceLocation resourceLocation2, ResourceLocation resourceLocation3, ShaderDefines shaderDefines, List list, List list2, Optional optional, DepthTestFunction depthTestFunction, PolygonMode polygonMode, boolean bl, boolean bl2, boolean bl3, boolean bl4, LogicOp logicOp, VertexFormat vertexFormat, VertexFormat.Mode mode, float f, float g ) { this.location = resourceLocation; this.vertexShader = resourceLocation2; this.fragmentShader = resourceLocation3; this.shaderDefines = shaderDefines; this.samplers = list; this.uniforms = list2; this.depthTestFunction = depthTestFunction; this.polygonMode = polygonMode; this.cull = bl; this.blendFunction = optional; this.writeColor = bl2; this.writeAlpha = bl3; this.writeDepth = bl4; this.colorLogic = logicOp; this.vertexFormat = vertexFormat; this.vertexFormatMode = mode; this.depthBiasScaleFactor = f; this.depthBiasConstant = g; } public String toString() { return this.location.toString(); } public DepthTestFunction getDepthTestFunction() { return this.depthTestFunction; } public PolygonMode getPolygonMode() { return this.polygonMode; } public boolean isCull() { return this.cull; } public LogicOp getColorLogic() { return this.colorLogic; } public Optional getBlendFunction() { return this.blendFunction; } public boolean isWriteColor() { return this.writeColor; } public boolean isWriteAlpha() { return this.writeAlpha; } public boolean isWriteDepth() { return this.writeDepth; } public float getDepthBiasScaleFactor() { return this.depthBiasScaleFactor; } public float getDepthBiasConstant() { return this.depthBiasConstant; } public ResourceLocation getLocation() { return this.location; } public VertexFormat getVertexFormat() { return this.vertexFormat; } public VertexFormat.Mode getVertexFormatMode() { return this.vertexFormatMode; } public ResourceLocation getVertexShader() { return this.vertexShader; } public ResourceLocation getFragmentShader() { return this.fragmentShader; } public ShaderDefines getShaderDefines() { return this.shaderDefines; } public List getSamplers() { return this.samplers; } public List getUniforms() { return this.uniforms; } public boolean wantsDepthTexture() { return this.depthTestFunction != DepthTestFunction.NO_DEPTH_TEST || this.depthBiasConstant != 0.0F || this.depthBiasScaleFactor != 0.0F || this.writeDepth; } public static RenderPipeline.Builder builder(RenderPipeline.Snippet... snippets) { RenderPipeline.Builder builder = new RenderPipeline.Builder(); for (RenderPipeline.Snippet snippet : snippets) { builder.withSnippet(snippet); } return builder; } @Environment(EnvType.CLIENT) @DontObfuscate public static class Builder { private Optional location = Optional.empty(); private Optional fragmentShader = Optional.empty(); private Optional vertexShader = Optional.empty(); private Optional definesBuilder = Optional.empty(); private Optional> samplers = Optional.empty(); private Optional> uniforms = Optional.empty(); private Optional depthTestFunction = Optional.empty(); private Optional polygonMode = Optional.empty(); private Optional cull = Optional.empty(); private Optional writeColor = Optional.empty(); private Optional writeAlpha = Optional.empty(); private Optional writeDepth = Optional.empty(); private Optional colorLogic = Optional.empty(); private Optional blendFunction = Optional.empty(); private Optional vertexFormat = Optional.empty(); private Optional vertexFormatMode = Optional.empty(); private float depthBiasScaleFactor; private float depthBiasConstant; Builder() { } public RenderPipeline.Builder withLocation(String string) { this.location = Optional.of(ResourceLocation.withDefaultNamespace(string)); return this; } public RenderPipeline.Builder withLocation(ResourceLocation resourceLocation) { this.location = Optional.of(resourceLocation); return this; } public RenderPipeline.Builder withFragmentShader(String string) { this.fragmentShader = Optional.of(ResourceLocation.withDefaultNamespace(string)); return this; } public RenderPipeline.Builder withFragmentShader(ResourceLocation resourceLocation) { this.fragmentShader = Optional.of(resourceLocation); return this; } public RenderPipeline.Builder withVertexShader(String string) { this.vertexShader = Optional.of(ResourceLocation.withDefaultNamespace(string)); return this; } public RenderPipeline.Builder withVertexShader(ResourceLocation resourceLocation) { this.vertexShader = Optional.of(resourceLocation); return this; } public RenderPipeline.Builder withShaderDefine(String string) { if (this.definesBuilder.isEmpty()) { this.definesBuilder = Optional.of(ShaderDefines.builder()); } ((ShaderDefines.Builder)this.definesBuilder.get()).define(string); return this; } public RenderPipeline.Builder withShaderDefine(String string, int i) { if (this.definesBuilder.isEmpty()) { this.definesBuilder = Optional.of(ShaderDefines.builder()); } ((ShaderDefines.Builder)this.definesBuilder.get()).define(string, i); return this; } public RenderPipeline.Builder withShaderDefine(String string, float f) { if (this.definesBuilder.isEmpty()) { this.definesBuilder = Optional.of(ShaderDefines.builder()); } ((ShaderDefines.Builder)this.definesBuilder.get()).define(string, f); return this; } public RenderPipeline.Builder withSampler(String string) { if (this.samplers.isEmpty()) { this.samplers = Optional.of(new ArrayList()); } ((List)this.samplers.get()).add(string); return this; } public RenderPipeline.Builder withUniform(String string, UniformType uniformType) { if (this.uniforms.isEmpty()) { this.uniforms = Optional.of(new ArrayList()); } ((List)this.uniforms.get()).add(new RenderPipeline.UniformDescription(string, uniformType)); return this; } public RenderPipeline.Builder withDepthTestFunction(DepthTestFunction depthTestFunction) { this.depthTestFunction = Optional.of(depthTestFunction); return this; } public RenderPipeline.Builder withPolygonMode(PolygonMode polygonMode) { this.polygonMode = Optional.of(polygonMode); return this; } public RenderPipeline.Builder withCull(boolean bl) { this.cull = Optional.of(bl); return this; } public RenderPipeline.Builder withBlend(BlendFunction blendFunction) { this.blendFunction = Optional.of(blendFunction); return this; } public RenderPipeline.Builder withoutBlend() { this.blendFunction = Optional.empty(); return this; } public RenderPipeline.Builder withColorWrite(boolean bl) { this.writeColor = Optional.of(bl); this.writeAlpha = Optional.of(bl); return this; } public RenderPipeline.Builder withColorWrite(boolean bl, boolean bl2) { this.writeColor = Optional.of(bl); this.writeAlpha = Optional.of(bl2); return this; } public RenderPipeline.Builder withDepthWrite(boolean bl) { this.writeDepth = Optional.of(bl); return this; } public RenderPipeline.Builder withColorLogic(LogicOp logicOp) { this.colorLogic = Optional.of(logicOp); return this; } public RenderPipeline.Builder withVertexFormat(VertexFormat vertexFormat, VertexFormat.Mode mode) { this.vertexFormat = Optional.of(vertexFormat); this.vertexFormatMode = Optional.of(mode); return this; } public RenderPipeline.Builder withDepthBias(float f, float g) { this.depthBiasScaleFactor = f; this.depthBiasConstant = g; return this; } void withSnippet(RenderPipeline.Snippet snippet) { if (snippet.vertexShader.isPresent()) { this.vertexShader = snippet.vertexShader; } if (snippet.fragmentShader.isPresent()) { this.fragmentShader = snippet.fragmentShader; } if (snippet.shaderDefines.isPresent()) { if (this.definesBuilder.isEmpty()) { this.definesBuilder = Optional.of(ShaderDefines.builder()); } ShaderDefines shaderDefines = (ShaderDefines)snippet.shaderDefines.get(); for (Entry entry : shaderDefines.values().entrySet()) { ((ShaderDefines.Builder)this.definesBuilder.get()).define((String)entry.getKey(), (String)entry.getValue()); } for (String string : shaderDefines.flags()) { ((ShaderDefines.Builder)this.definesBuilder.get()).define(string); } } snippet.samplers.ifPresent(list -> { if (this.samplers.isPresent()) { ((List)this.samplers.get()).addAll(list); } else { this.samplers = Optional.of(new ArrayList(list)); } }); snippet.uniforms.ifPresent(list -> { if (this.uniforms.isPresent()) { ((List)this.uniforms.get()).addAll(list); } else { this.uniforms = Optional.of(new ArrayList(list)); } }); if (snippet.depthTestFunction.isPresent()) { this.depthTestFunction = snippet.depthTestFunction; } if (snippet.cull.isPresent()) { this.cull = snippet.cull; } if (snippet.writeColor.isPresent()) { this.writeColor = snippet.writeColor; } if (snippet.writeAlpha.isPresent()) { this.writeAlpha = snippet.writeAlpha; } if (snippet.writeDepth.isPresent()) { this.writeDepth = snippet.writeDepth; } if (snippet.colorLogic.isPresent()) { this.colorLogic = snippet.colorLogic; } if (snippet.blendFunction.isPresent()) { this.blendFunction = snippet.blendFunction; } if (snippet.vertexFormat.isPresent()) { this.vertexFormat = snippet.vertexFormat; } if (snippet.vertexFormatMode.isPresent()) { this.vertexFormatMode = snippet.vertexFormatMode; } } public RenderPipeline.Snippet buildSnippet() { return new RenderPipeline.Snippet( this.vertexShader, this.fragmentShader, this.definesBuilder.map(ShaderDefines.Builder::build), this.samplers.map(Collections::unmodifiableList), this.uniforms.map(Collections::unmodifiableList), this.blendFunction, this.depthTestFunction, this.polygonMode, this.cull, this.writeColor, this.writeAlpha, this.writeDepth, this.colorLogic, this.vertexFormat, this.vertexFormatMode ); } public RenderPipeline build() { if (this.location.isEmpty()) { throw new IllegalStateException("Missing location"); } else if (this.vertexShader.isEmpty()) { throw new IllegalStateException("Missing vertex shader"); } else if (this.fragmentShader.isEmpty()) { throw new IllegalStateException("Missing fragment shader"); } else if (this.vertexFormat.isEmpty()) { throw new IllegalStateException("Missing vertex buffer format"); } else if (this.vertexFormatMode.isEmpty()) { throw new IllegalStateException("Missing vertex mode"); } else { return new RenderPipeline( (ResourceLocation)this.location.get(), (ResourceLocation)this.vertexShader.get(), (ResourceLocation)this.fragmentShader.get(), ((ShaderDefines.Builder)this.definesBuilder.orElse(ShaderDefines.builder())).build(), List.copyOf((Collection)this.samplers.orElse(new ArrayList())), (List)this.uniforms.orElse(Collections.emptyList()), this.blendFunction, (DepthTestFunction)this.depthTestFunction.orElse(DepthTestFunction.LEQUAL_DEPTH_TEST), (PolygonMode)this.polygonMode.orElse(PolygonMode.FILL), (Boolean)this.cull.orElse(true), (Boolean)this.writeColor.orElse(true), (Boolean)this.writeAlpha.orElse(true), (Boolean)this.writeDepth.orElse(true), (LogicOp)this.colorLogic.orElse(LogicOp.NONE), (VertexFormat)this.vertexFormat.get(), (VertexFormat.Mode)this.vertexFormatMode.get(), this.depthBiasScaleFactor, this.depthBiasConstant ); } } } @Environment(EnvType.CLIENT) @DontObfuscate public record Snippet( Optional vertexShader, Optional fragmentShader, Optional shaderDefines, Optional> samplers, Optional> uniforms, Optional blendFunction, Optional depthTestFunction, Optional polygonMode, Optional cull, Optional writeColor, Optional writeAlpha, Optional writeDepth, Optional colorLogic, Optional vertexFormat, Optional vertexFormatMode ) { } @Environment(EnvType.CLIENT) @DontObfuscate public record UniformDescription(String name, UniformType type) { } }