All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.ru.casperix.opengl.renderer.shader.ShaderBuffer.kt Maven / Gradle / Ivy

package ru.casperix.opengl.renderer.shader

import ru.casperix.math.vector.int32.Vector2i
import ru.casperix.misc.Disposable
import ru.casperix.misc.toString
import ru.casperix.opengl.core.*
import ru.casperix.opengl.renderer.util.ConsoleMagic

class ShaderBuffer(val vertex: String, val fragment: String, val geom: String?) : Disposable {
	private val GL_TRUE = 1
	private val GL_GEOMETRY_SHADER = -1

	val programId = glCreateProgram()

	init {
		val vertexShader = createShader(vertex, GL_VERTEX_SHADER)
		val fragmentShader = createShader(fragment, GL_FRAGMENT_SHADER)

		val geometryShader = if (geom != null) {
			createShader(geom, GL_GEOMETRY_SHADER)
		} else null

		glAttachShader(programId, vertexShader)
		if (geometryShader != null) glAttachShader(programId, geometryShader)
		glAttachShader(programId, fragmentShader)

		glLinkProgram(programId)
		val status = glGetProgrami(programId, GL_LINK_STATUS)
		if (status != GL_TRUE) {
			val info = glGetProgramInfoLog(programId)
			throw RuntimeException(info)
		}

		glDetachShader(programId, vertexShader)
		glDetachShader(programId, fragmentShader)
		glDeleteShader(vertexShader)
		glDeleteShader(fragmentShader)

		if (geometryShader != null) {
			glDetachShader(programId, geometryShader)
			glDeleteShader(geometryShader)
		}
	}

	override fun dispose() {
		glDeleteProgram(programId)
	}

	fun bind() {
		glUseProgram(programId)
	}

	fun unbind() {
		glUseProgram(0)
	}

	private fun createShader(source: String, gl_type: Int): Int {
		val shader = glCreateShader(gl_type)
		glShaderSource(shader, source)
		glCompileShader(shader)
		val status = glGetShaderi(shader, GL_COMPILE_STATUS)
		if (status != 1) {
			val info = glGetShaderInfoLog(shader) ?: "unknown gl-error"
			printShaderError(source, info)
			throw RuntimeException(info)
		}
		return shader
	}

	private fun parseErrorPosition(error: String): Vector2i? {
		val errorFirstLine = error.split(Regex("\n"), 2).firstOrNull() ?: ""
		val item = Regex("\\d+:\\d+").find(errorFirstLine)
		if (item != null) {
			val numbers = item.value.split(":").map { it.toInt() }
			if (numbers.size != 2) return null
			return Vector2i(numbers[0], numbers[1])
		}
		return null
	}

	private fun printShaderError(source: String, error: String) {
		val errorPosition = parseErrorPosition(error) ?: Vector2i(-1)

		val output = source.split("\n").mapIndexed { lineIndex, line ->
			val lineIndexFormatted = lineIndex.toString(3, ' ')

					if (lineIndex != errorPosition.y - 1) {
						ConsoleMagic.makeWhite(lineIndexFormatted) +"  $line"
					} else {
						ConsoleMagic.makeRed(lineIndexFormatted) + ConsoleMagic.makeRed("  $line <<<")
					}
		}
		println(output.joinToString("\n"))
	}


}







© 2015 - 2024 Weber Informatics LLC | Privacy Policy