package ocelot.desktop.graphics import ocelot.desktop.geometry.Transform2D import ocelot.desktop.util.{Resource, ResourceManager} import org.apache.logging.log4j.scala.Logging import org.lwjgl.opengl.GL20 import scala.io.Source class ShaderProgram(name: String) extends Logging with Resource { logger.info(s"Loading shader program ($name)") val fragmentShader: Int = createShader(Source.fromResource(s"ocelot/desktop/shader/$name.frag", getClass.getClassLoader), GL20.GL_FRAGMENT_SHADER, "fragment") val vertexShader: Int = createShader(Source.fromResource(s"ocelot/desktop/shader/$name.vert", getClass.getClassLoader), GL20.GL_VERTEX_SHADER, "vertex") val shaderProgram: Int = GL20.glCreateProgram() GL20.glAttachShader(shaderProgram, vertexShader) GL20.glAttachShader(shaderProgram, fragmentShader) GL20.glLinkProgram(shaderProgram) { val success = Array(0) GL20.glGetProgramiv(shaderProgram, GL20.GL_LINK_STATUS, success) if (success.head == 0) { val info = GL20.glGetProgramInfoLog(shaderProgram) logger.error(s"Failed to link shader program ($name)\n$info") throw new RuntimeException("Shader linkage failed") } } ResourceManager.registerResource(this) def freeResource(): Unit = { logger.debug(s"Destroyed shader program ($name)") GL20.glDeleteProgram(shaderProgram) GL20.glDeleteShader(vertexShader) GL20.glDeleteShader(fragmentShader) } def bind(): Unit = { GL20.glUseProgram(shaderProgram) } def set(name: String, transform: Transform2D): Unit = { bind() val array = transform.array ++ Array(0f, 0f, 1f) GL20.glUniformMatrix3fv(getLocation(name), true, array) } def set(name: String, v: Int): Unit = { bind() GL20.glUniform1i(getLocation(name), v) } private def getLocation(name: String): Int = { GL20.glGetUniformLocation(shaderProgram, name) } private def createShader(source: Source, ty: Int, s: String): Int = { val shader = GL20.glCreateShader(ty) GL20.glShaderSource(shader, source.mkString) GL20.glCompileShader(shader) val success = Array(0) GL20.glGetShaderiv(shader, GL20.GL_COMPILE_STATUS, success) if (success.head == 0) { val info = GL20.glGetShaderInfoLog(shader) logger.error(s"Failed to compile shader ($s)\n$info") throw new RuntimeException("Shader compilation failed") } source.close() shader } }