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

There is a newer version: 1.3.0
Show newest version
package ru.casperix.opengl.renderer.shader

import io.github.oshai.kotlinlogging.KotlinLogging
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 logger = KotlinLogging.logger { }
    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 <<<")
            }
        }

        logger.warn { output.joinToString("\n") }
    }


}







© 2015 - 2025 Weber Informatics LLC | Privacy Policy