From 26461deda4dc8695dacedefe50d976eb5e3d7714 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Sat, 7 Sep 2024 14:44:43 +0200 Subject: Add shader loading functionality [no changelog] --- .../mixins/InjectCustomShaderPrograms.java | 31 +++++++++++ .../kotlin/events/RegisterCustomShadersEvent.kt | 24 +++++++++ src/main/kotlin/util/render/FirmamentShaders.kt | 23 ++++++++ .../kotlin/util/render/RenderInWorldContext.kt | 4 +- .../shaders/core/firmament_rendertype_lines.fsh | 18 +++++++ .../shaders/core/firmament_rendertype_lines.json | 17 ++++++ .../shaders/core/firmament_rendertype_lines.vsh | 62 ++++++++++++++++++++++ 7 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java create mode 100644 src/main/kotlin/events/RegisterCustomShadersEvent.kt create mode 100644 src/main/kotlin/util/render/FirmamentShaders.kt create mode 100644 src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh create mode 100644 src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json create mode 100644 src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh (limited to 'src/main') diff --git a/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java b/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java new file mode 100644 index 0000000..5306e42 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java @@ -0,0 +1,31 @@ +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.datafixers.util.Pair; +import moe.nea.firmament.events.RegisterCustomShadersEvent; +import net.minecraft.client.gl.ShaderProgram; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.resource.ResourceFactory; +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.callback.CallbackInfo; + +import java.util.List; +import java.util.function.Consumer; + +@Mixin(GameRenderer.class) +public class InjectCustomShaderPrograms { + + @Inject(method = "loadPrograms", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;loadBlurPostProcessor(Lnet/minecraft/resource/ResourceFactory;)V", + shift = At.Shift.AFTER)) + void addFirmamentShaders( + ResourceFactory resourceFactory, CallbackInfo ci, + @Local(index = 3) List>> list + ) { + var event = new RegisterCustomShadersEvent(list, resourceFactory); + RegisterCustomShadersEvent.Companion.publish(event); + } +} diff --git a/src/main/kotlin/events/RegisterCustomShadersEvent.kt b/src/main/kotlin/events/RegisterCustomShadersEvent.kt new file mode 100644 index 0000000..2f6d1f8 --- /dev/null +++ b/src/main/kotlin/events/RegisterCustomShadersEvent.kt @@ -0,0 +1,24 @@ +package moe.nea.firmament.events + +import com.mojang.datafixers.util.Pair +import java.util.function.Consumer +import net.minecraft.client.gl.ShaderProgram +import net.minecraft.client.render.VertexFormat +import net.minecraft.resource.ResourceFactory +import moe.nea.firmament.Firmament + +data class RegisterCustomShadersEvent( + val list: MutableList>>, + val resourceFactory: ResourceFactory, +) : FirmamentEvent() { + companion object : FirmamentEventBus() + + fun register(name: String, vertexFormat: VertexFormat, saver: Consumer) { + require(name.startsWith("firmament_")) + try { + list.add(Pair.of(ShaderProgram(resourceFactory, name, vertexFormat), saver)) + } catch (ex: Exception) { + Firmament.logger.fatal("Could not load firmament shader $name", ex) + } + } +} diff --git a/src/main/kotlin/util/render/FirmamentShaders.kt b/src/main/kotlin/util/render/FirmamentShaders.kt new file mode 100644 index 0000000..1094bc2 --- /dev/null +++ b/src/main/kotlin/util/render/FirmamentShaders.kt @@ -0,0 +1,23 @@ +package moe.nea.firmament.util.render + +import net.minecraft.client.gl.ShaderProgram +import net.minecraft.client.render.RenderPhase +import net.minecraft.client.render.VertexFormats +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.RegisterCustomShadersEvent + +object FirmamentShaders { + + + private lateinit var _LINES: ShaderProgram + val LINES = RenderPhase.ShaderProgram({ _LINES }) + + @Subscribe + fun registerCustomShaders(event: RegisterCustomShadersEvent) { + event.register( + "firmament_rendertype_lines", + VertexFormats.LINES, + { _LINES = it }, + ) + } +} diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt index 775e8f3..75f2fad 100644 --- a/src/main/kotlin/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/util/render/RenderInWorldContext.kt @@ -56,7 +56,7 @@ class RenderInWorldContext private constructor( false, false, // do we need translucent? i dont think so RenderLayer.MultiPhaseParameters.builder() .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .program(RenderPhase.LINES_PROGRAM) + .program(FirmamentShaders.LINES) .build(false) ) } @@ -172,7 +172,7 @@ class RenderInWorldContext private constructor( points.zipWithNext().forEach { (a, b) -> val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) - .normalize() +// .normalize() val lastNormal0 = lastNormal ?: normal lastNormal = normal buffer.vertex(matrix.positionMatrix, a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh b/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh new file mode 100644 index 0000000..057f31f --- /dev/null +++ b/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh @@ -0,0 +1,18 @@ +#version 150 + +#moj_import + +uniform vec4 ColorModulator; +uniform float FogStart; +uniform float FogEnd; +uniform vec4 FogColor; + +in float vertexDistance; +in vec4 vertexColor; + +out vec4 fragColor; + +void main() { + vec4 color = vertexColor * ColorModulator; + fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor); +} diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json b/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json new file mode 100644 index 0000000..0828480 --- /dev/null +++ b/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json @@ -0,0 +1,17 @@ +{ + "vertex": "firmament_rendertype_lines", + "fragment": "firmament_rendertype_lines", + "samplers": [ + ], + "uniforms": [ + { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, + { "name": "LineWidth", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "ScreenSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] }, + { "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] } + ] +} diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh b/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh new file mode 100644 index 0000000..35892be --- /dev/null +++ b/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh @@ -0,0 +1,62 @@ +#version 150 + +#moj_import + +in vec3 Position; +in vec4 Color; +in vec3 Normal; + +uniform mat4 ModelViewMat; +uniform mat4 ProjMat; +uniform float LineWidth; +uniform vec2 ScreenSize; +uniform int FogShape; + +out float vertexDistance; +out vec4 vertexColor; + +const float VIEW_SHRINK = 1.0 - (1.0 / 256.0); +const mat4 VIEW_SCALE = mat4( + VIEW_SHRINK, 0.0, 0.0, 0.0, + 0.0, VIEW_SHRINK, 0.0, 0.0, + 0.0, 0.0, VIEW_SHRINK, 0.0, + 0.0, 0.0, 0.0, 1.0 +); + +void main() { + vec4 linePosStart = ProjMat * VIEW_SCALE * ModelViewMat * vec4(Position, 1.0); + vec4 linePosEnd = ProjMat * VIEW_SCALE * ModelViewMat * vec4(Position + Normal, 1.0); + + vec3 ndc1 = linePosStart.xyz / linePosStart.w; + vec3 ndc2 = linePosEnd.xyz / linePosEnd.w; + + bool linePosStartBehind = ndc1.z <= -1; + bool linePosEndBehind = ndc2.z <= -1; + + if ((linePosStartBehind && linePosEndBehind)) { + gl_Position = vec4(-2.0, -2.0, -2.0, 1.0); + return; // I don't care for these people + } + if (linePosStartBehind || linePosEndBehind) { + ndc1.z = 0.0; + ndc2.z = 0.0; + linePosStart.w = 1.0; + // TODO: use mx + b to find move the two coordinates around to extend lines + } + + vec2 lineScreenDirection = normalize((ndc2.xy - ndc1.xy) * ScreenSize); + vec2 lineOffset = vec2(-lineScreenDirection.y, lineScreenDirection.x) * LineWidth / ScreenSize; + + if (lineOffset.x < 0.0) { + lineOffset *= -1.0; + } + + if (gl_VertexID % 2 == 0) { + gl_Position = vec4((ndc1 + vec3(lineOffset, 0.0)) * linePosStart.w, linePosStart.w); + } else { + gl_Position = vec4((ndc1 - vec3(lineOffset, 0.0)) * linePosStart.w, linePosStart.w); + } + + vertexDistance = fog_distance(Position, FogShape); + vertexColor = Color; +} -- cgit