diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/FabricRenderPipeline.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/FabricRenderPipeline.java index 689b4bed21b..5b36882fe79 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/FabricRenderPipeline.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/FabricRenderPipeline.java @@ -17,9 +17,12 @@ package net.fabricmc.fabric.api.client.rendering.v1; import java.util.Optional; +import java.util.function.Consumer; import com.mojang.blaze3d.pipeline.RenderPipeline; +import net.fabricmc.fabric.impl.client.rendering.FabricRenderPipelineImpl; + /** * General purpose Fabric extensions to the {@link RenderPipeline} class. * @@ -35,6 +38,41 @@ default boolean usePipelineDrawModeForGui() { throw new AssertionError("Implemented in Mixin"); } + /** + * Creates a builder that when built would create this pipeline. + * Note that the caller must call {@link RenderPipeline.Builder#withLocation(net.minecraft.resources.Identifier)} returned builder before building. + * + * @return a builder that could build this pipeline + */ + default RenderPipeline.Builder toBuilder() { + RenderPipeline $self = (RenderPipeline) this; + RenderPipeline.Builder builder = RenderPipeline.builder() + .withLocation($self.getLocation()) + .withVertexShader($self.getVertexShader()) + .withFragmentShader($self.getFragmentShader()) + .withDepthTestFunction($self.getDepthTestFunction()) + .withPolygonMode($self.getPolygonMode()) + .withCull($self.isCull()) + .withColorLogic($self.getColorLogic()) + .withColorWrite($self.isWriteColor(), $self.isWriteAlpha()) + .withDepthWrite($self.isWriteDepth()) + .withVertexFormat($self.getVertexFormat(), $self.getVertexFormatMode()) + .withDepthBias($self.getDepthBiasScaleFactor(), $self.getDepthBiasConstant()) + .withUsePipelineDrawModeForGui($self.usePipelineDrawModeForGui()); + $self.getShaderDefines().values().forEach((v1, v2) -> ((FabricRenderPipelineImpl.BuilderImpl) builder).fabric$getShaderDefines().define(v1, v2)); + $self.getShaderDefines().flags().forEach(flag -> ((FabricRenderPipelineImpl.BuilderImpl) builder).fabric$getShaderDefines().define(flag)); + return builder; + } + + /** + * Creates a snippet that describes this pipeline. + * + * @return a snippet that describes this pipeline + */ + default RenderPipeline.Snippet toSnippet() { + return toBuilder().buildSnippet(); + } + /** * General purpose Fabric extensions to the {@link RenderPipeline.Builder} class. * @@ -76,6 +114,18 @@ default Optional usePipelineDrawModeForGui() { throw new AssertionError("Implemented in Mixin"); } + /** + * Creates a new snippet that is identical to this one aside from the changes induced by {@code mutator}. + * + * @param mutator the changes to make to this snippet + * @return a new snippet identical to this one aside from the changes applied by mutator + */ + default RenderPipeline.Snippet with(Consumer mutator) { + RenderPipeline.Builder builder = RenderPipeline.builder((RenderPipeline.Snippet) this); + mutator.accept(builder); + return builder.buildSnippet(); + } + /** * Creates a new snippet with the specified pipeline draw mode for GUI rendering. * diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/FabricRenderPipelineImpl.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/FabricRenderPipelineImpl.java index 41480d11d39..08dd14e1d7a 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/FabricRenderPipelineImpl.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/FabricRenderPipelineImpl.java @@ -16,8 +16,14 @@ package net.fabricmc.fabric.impl.client.rendering; +import net.minecraft.client.renderer.ShaderDefines; + import net.fabricmc.fabric.api.client.rendering.v1.FabricRenderPipeline; public interface FabricRenderPipelineImpl extends FabricRenderPipeline { void fabric$setUsePipelineDrawModeForGuiSetter(boolean usePipelineDrawModeForGui); + + interface BuilderImpl extends FabricRenderPipeline.Builder { + ShaderDefines.Builder fabric$getShaderDefines(); + } } diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/RenderPipelineBuilderMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/RenderPipelineBuilderMixin.java index 141a5335b91..7452bdd625b 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/RenderPipelineBuilderMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/RenderPipelineBuilderMixin.java @@ -29,6 +29,7 @@ import com.mojang.blaze3d.platform.PolygonMode; import com.mojang.blaze3d.vertex.VertexFormat; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -37,12 +38,13 @@ import net.minecraft.client.renderer.ShaderDefines; import net.minecraft.resources.Identifier; -import net.fabricmc.fabric.api.client.rendering.v1.FabricRenderPipeline; import net.fabricmc.fabric.impl.client.rendering.FabricRenderPipelineImpl; import net.fabricmc.fabric.impl.client.rendering.FabricRenderPipelineInternals; @Mixin(RenderPipeline.Builder.class) -class RenderPipelineBuilderMixin implements FabricRenderPipeline.Builder { +class RenderPipelineBuilderMixin implements FabricRenderPipelineImpl.BuilderImpl { + @Shadow + private Optional definesBuilder; @Unique private Optional usePipelineDrawModeForGui = Optional.empty(); @@ -102,4 +104,13 @@ private RenderPipeline copyUsePipelineDrawModeForGuiToPipeline(RenderPipeline or ((FabricRenderPipelineImpl) original).fabric$setUsePipelineDrawModeForGuiSetter(this.usePipelineDrawModeForGui.orElse(false)); return original; } + + @Override + public ShaderDefines.Builder fabric$getShaderDefines() { + if (this.definesBuilder.isEmpty()) { + this.definesBuilder = Optional.of(ShaderDefines.builder()); + } + + return definesBuilder.orElseThrow(); + } }