aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/utils/shader
diff options
context:
space:
mode:
authorVixid <52578495+VixidDev@users.noreply.github.com>2023-10-14 10:05:48 +0100
committerGitHub <noreply@github.com>2023-10-14 11:05:48 +0200
commit16ef943b3c2ce8db2331332261143a12bdba61cf (patch)
tree52c764205ef2464c62b05e3585390b61c69bcdda /src/main/java/at/hannibal2/skyhanni/utils/shader
parentbfae99cb54988568b2752c7d6a8d3d5babed1bbc (diff)
downloadskyhanni-16ef943b3c2ce8db2331332261143a12bdba61cf.tar.gz
skyhanni-16ef943b3c2ce8db2331332261143a12bdba61cf.tar.bz2
skyhanni-16ef943b3c2ce8db2331332261143a12bdba61cf.zip
Feature: SBA Chroma but in SH (#487)
Porting SBA's chroma into SkyHanni with many more options and chroma everything. #487
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/utils/shader')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt55
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt124
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt87
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt45
4 files changed, 311 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt
new file mode 100644
index 000000000..f198f7e7a
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/Shader.kt
@@ -0,0 +1,55 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.shader.ShaderLinkHelper
+import org.apache.commons.lang3.StringUtils
+import org.lwjgl.opengl.GL11
+import java.util.function.Supplier
+
+/**
+ * Superclass for shader objects to compile and attach vertex and fragment shaders to the shader program
+ *
+ * Modified class from SkyblockAddons
+ *
+ * Credit: [Shader.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/Shader.java)
+ */
+abstract class Shader(vertex: String, fragment: String) {
+
+ var shaderProgram: Int = ShaderLinkHelper.getStaticShaderLinkHelper().createProgram()
+ private val uniforms: MutableList<Uniform<*>> = mutableListOf()
+
+ init {
+ val vertexShaderID = ShaderManager.loadShader(ShaderType.VERTEX, vertex)
+ ShaderManager.attachShader(shaderProgram, vertexShaderID)
+ val fragmentShaderID = ShaderManager.loadShader(ShaderType.FRAGMENT, fragment)
+ ShaderManager.attachShader(shaderProgram, fragmentShaderID)
+
+ ShaderHelper.glLinkProgram(shaderProgram)
+
+ val linkStatus = ShaderHelper.glGetProgrami(shaderProgram, ShaderHelper.GL_LINK_STATUS)
+ if (linkStatus == GL11.GL_FALSE) {
+ LorenzUtils.consoleLog(
+ "Error occurred when linking program with Vertex Shader: $vertex and Fragment Shader: $fragment : " +
+ StringUtils.trim(ShaderHelper.glGetProgramInfoLog(shaderProgram, 1024))
+ )
+ }
+
+ this.registerUniforms()
+ }
+
+ abstract fun registerUniforms()
+
+ fun updateUniforms() {
+ for (uniform in uniforms) {
+ uniform.update()
+ }
+ }
+
+ fun enable() = ShaderHelper.glUseProgram(shaderProgram)
+
+ fun disable() = ShaderHelper.glUseProgram(0)
+
+ fun <T> registerUniform(uniformType: Uniform.UniformType<T>, name: String, uniformValuesSupplier: Supplier<T>) {
+ uniforms.add(Uniform(this, uniformType, name, uniformValuesSupplier))
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt
new file mode 100644
index 000000000..e554a4098
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt
@@ -0,0 +1,124 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import org.lwjgl.opengl.*
+
+/**
+ * Class to check shaders support, OpenGL capabilities, and shader helper functions
+ *
+ * Modified class from SkyblockAddons
+ *
+ * Credit: [ShaderHelper.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/ShaderHelper.java)
+ */
+class ShaderHelper {
+ companion object {
+ private var SHADERS_SUPPORTED: Boolean
+
+ private var USING_ARB_SHADERS: Boolean
+
+ var GL_LINK_STATUS: Int
+ var GL_COMPILE_STATUS: Int
+ var GL_VERTEX_SHADER: Int
+ var GL_FRAGMENT_SHADER: Int
+
+ init {
+ val capabilities: ContextCapabilities = GLContext.getCapabilities()
+
+ // Check OpenGL 2.0 Capabilities
+ val openGL20supported = capabilities.OpenGL20
+ SHADERS_SUPPORTED = openGL20supported ||
+ capabilities.GL_ARB_vertex_shader &&
+ capabilities.GL_ARB_fragment_shader &&
+ capabilities.GL_ARB_shader_objects
+
+ var log = "Shaders are"
+ if (!SHADERS_SUPPORTED) log += " not"
+ log += " available. "
+
+ if (SHADERS_SUPPORTED) {
+ if (capabilities.OpenGL20) {
+ log += "OpenGL 2.0 is supported. "
+ USING_ARB_SHADERS = false
+ GL_LINK_STATUS = GL20.GL_LINK_STATUS
+ GL_COMPILE_STATUS = GL20.GL_COMPILE_STATUS
+ GL_VERTEX_SHADER = GL20.GL_VERTEX_SHADER
+ GL_FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER
+ } else {
+ log += "ARB_shader_objects, ARB_vertex_shader, and ARB_fragment_shader are supported. "
+ USING_ARB_SHADERS = true
+ GL_LINK_STATUS = ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB
+ GL_COMPILE_STATUS = ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB
+ GL_VERTEX_SHADER = ARBVertexShader.GL_VERTEX_SHADER_ARB
+ GL_FRAGMENT_SHADER = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB
+ }
+ } else {
+ log += "OpenGL 2.0 is not supported and ARB_shader_objects, ARB_vertex_shader, and ARB_fragment_shader are not supported."
+ USING_ARB_SHADERS = false
+ GL_LINK_STATUS = GL11.GL_FALSE
+ GL_COMPILE_STATUS = GL11.GL_FALSE
+ GL_VERTEX_SHADER = GL11.GL_FALSE
+ GL_FRAGMENT_SHADER = GL11.GL_FALSE
+ }
+
+ LorenzUtils.consoleLog(log)
+ }
+
+ fun glLinkProgram(program: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glLinkProgramARB(program) else GL20.glLinkProgram(program)
+ }
+
+ fun glGetProgramInfoLog(program: Int, maxLength: Int) : String {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetInfoLogARB(program, maxLength) else GL20.glGetProgramInfoLog(program, maxLength)
+ }
+
+ fun glGetProgrami(program: Int, pname: Int) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetObjectParameteriARB(program, pname) else GL20.glGetProgrami(program, pname)
+ }
+
+ fun glUseProgram(program: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glUseProgramObjectARB(program) else GL20.glUseProgram(program)
+ }
+
+ fun glAttachShader(program: Int, shaderIn: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glAttachObjectARB(program, shaderIn) else GL20.glAttachShader(program, shaderIn)
+ }
+
+ fun glCreateShader(type: Int) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glCreateShaderObjectARB(type) else GL20.glCreateShader(type)
+ }
+
+ fun glShaderSource(shader: Int, source: CharSequence) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glShaderSourceARB(shader, source) else GL20.glShaderSource(shader, source)
+ }
+
+ fun glCompileShader(shader: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glCompileShaderARB(shader) else GL20.glCompileShader(shader)
+ }
+
+ fun glGetShaderi(shader: Int, pname: Int) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetObjectParameteriARB(shader, pname) else GL20.glGetShaderi(shader, pname)
+ }
+
+ fun glGetShaderInfoLog(shader: Int, maxLength: Int) : String {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetInfoLogARB(shader, maxLength) else GL20.glGetShaderInfoLog(shader, maxLength)
+ }
+
+ fun glDeleteShader(shader: Int) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glDeleteObjectARB(shader) else GL20.glDeleteShader(shader)
+ }
+
+ fun glUniform1f(location: Int, v0: Float) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glUniform1fARB(location, v0) else GL20.glUniform1f(location, v0)
+ }
+
+ fun glUniform3f(location: Int, v0: Float, v1: Float, v2: Float) {
+ if (USING_ARB_SHADERS) ARBShaderObjects.glUniform3fARB(location, v0, v1, v2) else GL20.glUniform3f(location, v0, v1, v2)
+ }
+
+ fun glGetUniformLocation(program: Int, name: CharSequence) : Int {
+ return if (USING_ARB_SHADERS) ARBShaderObjects.glGetUniformLocationARB(program, name) else GL20.glGetUniformLocation(program, name)
+ }
+
+ fun areShadersSupported() = SHADERS_SUPPORTED
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt
new file mode 100644
index 000000000..e7eb48f11
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt
@@ -0,0 +1,87 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import at.hannibal2.skyhanni.features.chroma.ChromaShader
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.util.ResourceLocation
+import org.apache.commons.lang3.StringUtils
+import java.io.BufferedReader
+import java.io.InputStreamReader
+
+/**
+ * Object to handle shaders for SkyHanni
+ */
+object ShaderManager {
+
+ /**
+ * For any future shaders add the object instance in this enum and
+ * in the when expression
+ */
+ enum class Shaders(val shader: Shader) {
+ CHROMA(ChromaShader.INSTANCE);
+
+ companion object {
+ fun getShaderInstance(shaderName: String) : Shader? = when (shaderName) {
+ "chroma" -> CHROMA.shader
+ else -> {
+ null
+ }
+ }
+ }
+ }
+
+ private val shaders: MutableMap<String, Shader> = mutableMapOf()
+ private var activeShader: Shader? = null
+
+ fun enableShader(shaderName: String) {
+ var shader = shaders[shaderName]
+
+ if (shader == null) {
+ shader = Shaders.getShaderInstance(shaderName)
+ if (shader == null) return
+ shaders[shaderName] = shader
+ }
+
+ activeShader = shader
+ shader.enable()
+ shader.updateUniforms()
+ }
+
+ fun attachShader(shaderProgram: Int, shaderID: Int) {
+ ShaderHelper.glAttachShader(shaderProgram, shaderID)
+ }
+
+ fun disableShader() {
+ if (activeShader == null) return
+
+ activeShader?.disable()
+ activeShader = null
+ }
+
+ fun loadShader(type: ShaderType, fileName: String) : Int {
+ val resourceLocation = ResourceLocation("skyhanni:shaders/$fileName${type.extension}")
+
+ val source = StringBuilder()
+
+ val inputStream = Minecraft.getMinecraft().resourceManager.getResource(resourceLocation).inputStream
+ BufferedReader(InputStreamReader(inputStream)).forEachLine {
+ source.append(it).append("\n")
+ }
+
+ val shaderID = ShaderHelper.glCreateShader(type.shaderType)
+ ShaderHelper.glShaderSource(shaderID, source.toString())
+ ShaderHelper.glCompileShader(shaderID)
+
+ if (ShaderHelper.glGetShaderi(shaderID, ShaderHelper.GL_COMPILE_STATUS) == 0) {
+ LorenzUtils.consoleLog("Error occurred when compiling shader $fileName${type.extension} : " +
+ StringUtils.trim(ShaderHelper.glGetShaderInfoLog(shaderID, 1024)))
+ }
+
+ return shaderID
+ }
+}
+
+enum class ShaderType(val extension: String, val shaderType: Int) {
+ VERTEX(".vsh", ShaderHelper.GL_VERTEX_SHADER),
+ FRAGMENT(".fsh", ShaderHelper.GL_FRAGMENT_SHADER)
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt
new file mode 100644
index 000000000..e87ea3b22
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt
@@ -0,0 +1,45 @@
+package at.hannibal2.skyhanni.utils.shader
+
+import java.util.*
+import java.util.function.Supplier
+
+/**
+ * Class to handle shader uniform types
+ *
+ * Modified from SkyblockAddons
+ *
+ * Credit: [Uniform.java](https://github.com/BiscuitDevelopment/SkyblockAddons/blob/main/src/main/java/codes/biscuit/skyblockaddons/shader/Uniform.java)
+ */
+class Uniform<T>(
+ shader: Shader,
+ private val uniformType: UniformType<T>,
+ val name: String,
+ private val uniformValuesSupplier: Supplier<T>
+) {
+
+ class UniformType<T> {
+ companion object {
+ val FLOAT: UniformType<Float> = UniformType()
+ val VEC3: UniformType<FloatArray> = UniformType()
+ val BOOL: UniformType<Boolean> = UniformType()
+ }
+ }
+
+ private val uniformID: Int = ShaderHelper.glGetUniformLocation(shader.shaderProgram, name)
+ private var previousUniformValue: T? = null
+
+ fun update() {
+ val newUniformValue: T = uniformValuesSupplier.get()
+ if (!Objects.deepEquals(previousUniformValue, newUniformValue)) {
+ when (uniformType) {
+ UniformType.FLOAT -> ShaderHelper.glUniform1f(uniformID, (newUniformValue as Float))
+ UniformType.VEC3 -> {
+ val values = newUniformValue as FloatArray
+ ShaderHelper.glUniform3f(uniformID, values[0], values[1], values[2])
+ }
+ UniformType.BOOL -> ShaderHelper.glUniform1f(uniformID, if (newUniformValue as Boolean) 1f else 0f)
+ }
+ previousUniformValue = newUniformValue
+ }
+ }
+} \ No newline at end of file