-
Notifications
You must be signed in to change notification settings - Fork 421
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add registry for core shaders in custom namespaces (#3416)
* Add registry for core shaders in custom namespaces (#2901) * Add registry for core shaders in custom namespaces * Apply suggestions from code review Co-authored-by: modmuss50 <[email protected]> * Use Identifier.NAMESPACE_SEPARATOR instead of ":" * Remove fabric_ prefixes from mixins * Move test rendering to lower-right corner for test screenshots --------- Co-authored-by: modmuss50 <[email protected]> * Reorder imports to comply with checkstyle * Rename some classes * Fix compilation error in test mod --------- Co-authored-by: Juuz <[email protected]> Co-authored-by: modmuss50 <[email protected]>
- Loading branch information
1 parent
0dc92ab
commit b7f3cf3
Showing
13 changed files
with
418 additions
and
2 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
...main/java/net/fabricmc/fabric/api/client/rendering/v1/CoreShaderRegistrationCallback.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.api.client.rendering.v1; | ||
|
||
import java.io.IOException; | ||
import java.util.function.Consumer; | ||
|
||
import org.jetbrains.annotations.ApiStatus; | ||
|
||
import net.minecraft.client.render.Shader; | ||
import net.minecraft.client.render.VertexFormat; | ||
import net.minecraft.util.Identifier; | ||
|
||
import net.fabricmc.fabric.api.event.Event; | ||
import net.fabricmc.fabric.api.event.EventFactory; | ||
|
||
/** | ||
* Called when core shaders ({@linkplain Shader shader programs} loaded from {@code assets/<namespace>/shaders/core}) | ||
* are loaded to register custom modded shaders. | ||
* | ||
* <p>Fabric API also modifies the {@code #moj_import} feature in core shaders to accept | ||
* arbitrary namespaces for shaders loaded using the {@code <filename.glsl>} syntax. | ||
* For example, {@code #moj_import <my_mod:test.glsl>} would import the shader from | ||
* {@code assets/my_mod/shaders/include/test.glsl}. | ||
*/ | ||
@FunctionalInterface | ||
public interface CoreShaderRegistrationCallback { | ||
Event<CoreShaderRegistrationCallback> EVENT = EventFactory.createArrayBacked(CoreShaderRegistrationCallback.class, callbacks -> context -> { | ||
for (CoreShaderRegistrationCallback callback : callbacks) { | ||
callback.registerShaders(context); | ||
} | ||
}); | ||
|
||
/** | ||
* Registers core shaders using the registration context. | ||
* | ||
* @param context the registration context | ||
*/ | ||
void registerShaders(RegistrationContext context) throws IOException; | ||
|
||
/** | ||
* A context object used to create and register core shader programs. | ||
* | ||
* <p>This is not meant for implementation by users of the API. | ||
*/ | ||
@ApiStatus.NonExtendable | ||
interface RegistrationContext { | ||
/** | ||
* Creates and registers a core shader program. | ||
* | ||
* <p>The program is loaded from {@code assets/<namespace>/shaders/core/<path>.json}. | ||
* | ||
* @param id the program ID | ||
* @param vertexFormat the vertex format used by the shader | ||
* @param loadCallback a callback that is called when the shader program has been successfully loaded | ||
*/ | ||
void register(Identifier id, VertexFormat vertexFormat, Consumer<Shader> loadCallback) throws IOException; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...ic-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/FabricShader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.impl.client.rendering; | ||
|
||
import java.io.IOException; | ||
|
||
import net.minecraft.client.render.Shader; | ||
import net.minecraft.client.render.VertexFormat; | ||
import net.minecraft.resource.ResourceFactory; | ||
import net.minecraft.util.Identifier; | ||
|
||
public final class FabricShader extends Shader { | ||
public FabricShader(ResourceFactory factory, Identifier name, VertexFormat format) throws IOException { | ||
super(factory, name.toString(), format); | ||
} | ||
|
||
/** | ||
* Rewrites the input string containing an identifier | ||
* with the namespace of the id in the front instead of in the middle. | ||
* | ||
* <p>Example: {@code shaders/core/my_mod:xyz} -> {@code my_mod:shaders/core/xyz} | ||
* | ||
* @param input the raw input string | ||
* @param containedId the ID contained within the input string | ||
* @return the corrected full ID string | ||
*/ | ||
public static String rewriteAsId(String input, String containedId) { | ||
Identifier contained = new Identifier(containedId); | ||
return contained.getNamespace() + Identifier.NAMESPACE_SEPARATOR + input.replace(containedId, contained.getPath()); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/shader/GameRendererMixin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.mixin.client.rendering.shader; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
import java.util.function.Consumer; | ||
|
||
import com.mojang.datafixers.util.Pair; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.Inject; | ||
import org.spongepowered.asm.mixin.injection.Slice; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | ||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; | ||
|
||
import net.minecraft.client.render.GameRenderer; | ||
import net.minecraft.client.render.Shader; | ||
import net.minecraft.resource.ResourceManager; | ||
|
||
import net.fabricmc.fabric.api.client.rendering.v1.CoreShaderRegistrationCallback; | ||
import net.fabricmc.fabric.impl.client.rendering.FabricShader; | ||
|
||
/** | ||
* Implements custom core shader registration (CoreShaderRegistrationCallback). | ||
*/ | ||
@Mixin(GameRenderer.class) | ||
abstract class GameRendererMixin { | ||
@Inject( | ||
method = "loadShaders", | ||
at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", remap = false, shift = At.Shift.AFTER), | ||
slice = @Slice(from = @At(value = "NEW", target = "net/minecraft/client/render/Shader", ordinal = 0)), | ||
locals = LocalCapture.CAPTURE_FAILHARD | ||
) | ||
private void registerShaders(ResourceManager factory, CallbackInfo info, List<?> shaderStages, List<Pair<Shader, Consumer<Shader>>> programs) throws IOException { | ||
CoreShaderRegistrationCallback.RegistrationContext context = (id, vertexFormat, loadCallback) -> { | ||
Shader program = new FabricShader(factory, id, vertexFormat); | ||
programs.add(Pair.of(program, loadCallback)); | ||
}; | ||
CoreShaderRegistrationCallback.EVENT.invoker().registerShaders(context); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
...in/java/net/fabricmc/fabric/mixin/client/rendering/shader/ShaderImportProcessorMixin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.mixin.client.rendering.shader; | ||
|
||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Unique; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.Inject; | ||
import org.spongepowered.asm.mixin.injection.ModifyVariable; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; | ||
|
||
import net.minecraft.util.Identifier; | ||
|
||
import net.fabricmc.fabric.impl.client.rendering.FabricShader; | ||
|
||
/** | ||
* Lets modded shaders {@code #moj_import} shaders from any namespace with the | ||
* {@code <>} syntax. | ||
*/ | ||
@Mixin(targets = "net.minecraft.client.render.Shader$1") | ||
abstract class ShaderImportProcessorMixin { | ||
@Unique | ||
private String capturedImport; | ||
|
||
@Inject(method = "loadImport", at = @At("HEAD")) | ||
private void captureImport(boolean inline, String name, CallbackInfoReturnable<String> info) { | ||
capturedImport = name; | ||
} | ||
|
||
@ModifyVariable(method = "loadImport", at = @At("STORE"), ordinal = 0, argsOnly = true) | ||
private String modifyImportId(String id, boolean inline) { | ||
if (!inline && capturedImport.contains(String.valueOf(Identifier.NAMESPACE_SEPARATOR))) { | ||
return FabricShader.rewriteAsId(id, capturedImport); | ||
} | ||
|
||
return id; | ||
} | ||
|
||
@Inject(method = "loadImport", at = @At("RETURN")) | ||
private void uncaptureImport(boolean inline, String name, CallbackInfoReturnable<String> info) { | ||
capturedImport = null; | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
...ering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/shader/ShaderMixin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.mixin.client.rendering.shader; | ||
|
||
import org.spongepowered.asm.mixin.Final; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Shadow; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.ModifyArg; | ||
import org.spongepowered.asm.mixin.injection.ModifyVariable; | ||
|
||
import net.minecraft.client.gl.Program; | ||
import net.minecraft.client.render.Shader; | ||
import net.minecraft.resource.ResourceFactory; | ||
import net.minecraft.util.Identifier; | ||
|
||
import net.fabricmc.fabric.impl.client.rendering.FabricShader; | ||
|
||
@Mixin(Shader.class) | ||
abstract class ShaderMixin { | ||
@Shadow | ||
@Final | ||
private String name; | ||
|
||
// Allow loading FabricShaderPrograms from arbitrary namespaces. | ||
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;<init>(Ljava/lang/String;)V"), allow = 1) | ||
private String modifyProgramId(String id) { | ||
if ((Object) this instanceof FabricShader) { | ||
return FabricShader.rewriteAsId(id, name); | ||
} | ||
|
||
return id; | ||
} | ||
|
||
// Allow loading shader stages from arbitrary namespaces. | ||
@ModifyVariable(method = "loadProgram", at = @At("STORE"), ordinal = 1) | ||
private static String modifyStageId(String id, ResourceFactory factory, Program.Type type, String name) { | ||
if (name.contains(String.valueOf(Identifier.NAMESPACE_SEPARATOR))) { | ||
return FabricShader.rewriteAsId(id, name); | ||
} | ||
|
||
return id; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...ering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/client/HudAndShaderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.test.rendering.client; | ||
|
||
import com.mojang.blaze3d.systems.RenderSystem; | ||
|
||
import net.minecraft.client.MinecraftClient; | ||
import net.minecraft.client.render.BufferBuilder; | ||
import net.minecraft.client.render.BufferRenderer; | ||
import net.minecraft.client.render.Shader; | ||
import net.minecraft.client.render.Tessellator; | ||
import net.minecraft.client.render.VertexFormat; | ||
import net.minecraft.client.render.VertexFormats; | ||
import net.minecraft.client.util.Window; | ||
import net.minecraft.util.Identifier; | ||
import net.minecraft.util.math.Matrix4f; | ||
|
||
import net.fabricmc.api.ClientModInitializer; | ||
import net.fabricmc.fabric.api.client.rendering.v1.CoreShaderRegistrationCallback; | ||
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; | ||
|
||
/** | ||
* Tests {@link HudRenderCallback} and {@link CoreShaderRegistrationCallback} by drawing a green rectangle | ||
* in the lower-right corner of the screen. | ||
*/ | ||
public class HudAndShaderTest implements ClientModInitializer { | ||
private static Shader testShader; | ||
|
||
@Override | ||
public void onInitializeClient() { | ||
CoreShaderRegistrationCallback.EVENT.register(context -> { | ||
// Register a custom shader taking POSITION vertices. | ||
Identifier id = new Identifier("fabric-rendering-v1-testmod", "test"); | ||
context.register(id, VertexFormats.POSITION, program -> testShader = program); | ||
}); | ||
|
||
HudRenderCallback.EVENT.register((matrices, tickDelta) -> { | ||
MinecraftClient client = MinecraftClient.getInstance(); | ||
Window window = client.getWindow(); | ||
int x = window.getScaledWidth() - 15; | ||
int y = window.getScaledHeight() - 15; | ||
RenderSystem.setShader(() -> testShader); | ||
RenderSystem.setShaderColor(0f, 1f, 0f, 1f); | ||
Matrix4f positionMatrix = matrices.peek().getPositionMatrix(); | ||
BufferBuilder buffer = Tessellator.getInstance().getBuffer(); | ||
buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION); | ||
buffer.vertex(positionMatrix, x, y, 50).next(); | ||
buffer.vertex(positionMatrix, x, y + 10, 50).next(); | ||
buffer.vertex(positionMatrix, x + 10, y + 10, 50).next(); | ||
buffer.vertex(positionMatrix, x + 10, y, 50).next(); | ||
buffer.end(); | ||
BufferRenderer.draw(buffer); | ||
// Reset shader color | ||
RenderSystem.setShaderColor(1f, 1f, 1f, 1f); | ||
}); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
...ndering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/shaders/core/test.fsh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#version 150 | ||
|
||
#moj_import <fabric-rendering-v1-testmod:test_include.glsl> | ||
|
||
uniform vec4 ColorModulator; | ||
out vec4 fragColor; | ||
|
||
void main() { | ||
fragColor = applyColor(vec4(1.0, 1.0, 1.0, 1.0), ColorModulator); | ||
} |
Oops, something went wrong.