From 26461deda4dc8695dacedefe50d976eb5e3d7714 Mon Sep 17 00:00:00 2001
From: Linnea Gräf <nea@nea.moe>
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')

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<Pair<ShaderProgram, Consumer<ShaderProgram>>> 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<Pair<ShaderProgram, Consumer<ShaderProgram>>>,
+    val resourceFactory: ResourceFactory,
+) : FirmamentEvent() {
+    companion object : FirmamentEventBus<RegisterCustomShadersEvent>()
+
+    fun register(name: String, vertexFormat: VertexFormat, saver: Consumer<ShaderProgram>) {
+        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 <fog.glsl>
+
+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 <fog.glsl>
+
+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