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

commonMain.ru.casperix.opengl.renderer.ShaderProvider.kt Maven / Gradle / Ivy

package ru.casperix.opengl.renderer

import io.github.oshai.kotlinlogging.KotlinLogging
import ru.casperix.opengl.core.misc.ShaderFactory
import ru.casperix.opengl.renderer.exp.TileMapMaterial
import ru.casperix.opengl.renderer.generated.Resources
import ru.casperix.opengl.renderer.impl.ShaderAttributes
import ru.casperix.opengl.renderer.impl.ShaderLightModel
import ru.casperix.opengl.renderer.impl.ShaderSourceAttribute
import ru.casperix.opengl.renderer.shader.ShaderBuffer
import ru.casperix.opengl.renderer.shader.ShaderController
import ru.casperix.renderer.material.*
import ru.casperix.renderer.vector.vertex.ColorFormat
import ru.casperix.renderer.vector.vertex.VertexAttributes

@ExperimentalUnsignedTypes
class ShaderProvider() {
    private val logger = KotlinLogging.logger { }

    private var shaderByAttributesConfig:OpenGlRendererConfig? = null
    private val shaderByAttributes = mutableMapOf()

    private val simpleShader = ShaderReference(Resources.shader2d_vert, Resources.shader2d_frag)

    class ShaderReference(val vertexShaderSource: String, val fragmentShaderSource: String)

    data class ShaderKey(val attributes: VertexAttributes, val material: Material)

    fun getOrCreate(
        vertexAttributes: VertexAttributes,
        material: Material,
        config: OpenGlRendererConfig,
    ): ShaderController {

        if (shaderByAttributesConfig != config) {
            shaderByAttributes.clear()
            shaderByAttributesConfig = config
        }

        val shaderAttributes = createShaderAttributes(vertexAttributes, material, config)
        return shaderByAttributes.getOrPut(shaderAttributes) {
            createSimpleShader(shaderAttributes, config)
        }
    }

    private fun getSource(source: ColorSource?): ShaderSourceAttribute? =
        when (source) {
            is ConstantColorSource -> ShaderSourceAttribute.CONST
            is TextureColorSource -> ShaderSourceAttribute.TEXTURE
            else -> null
        }

    private fun getSource(source: Vector3Source?): ShaderSourceAttribute? =
        when (source) {
            is ConstantVector3Source -> ShaderSourceAttribute.CONST
            is TextureVector3Source -> ShaderSourceAttribute.TEXTURE
            else -> null
        }

    private fun getSource(source: Vector2Source?): ShaderSourceAttribute? =
        when (source) {
            is ConstantVector2Source -> ShaderSourceAttribute.CONST
            is TextureVector2Source -> ShaderSourceAttribute.TEXTURE
            else -> null
        }

    private fun getSource(source: Vector1Source?): ShaderSourceAttribute? =
        when (source) {
            is ConstantVector1Source -> ShaderSourceAttribute.CONST
            is TextureVector1Source -> ShaderSourceAttribute.TEXTURE
            else -> null
        }

    private fun createShaderAttributes(vertexAttributes: VertexAttributes, material: Material, config: OpenGlRendererConfig): ShaderAttributes {
        return when (material) {
            is SimpleMaterial -> {
                val materialColorType = getSource(material.colorSource)
                val materialOpacityType = getSource(material.opacitySource)

                val hasVertexColor = vertexAttributes.color == ColorFormat.BGR || vertexAttributes.color == ColorFormat.RGB
                val hasVertexOpacity = vertexAttributes.hasOpacity

                ShaderAttributes(
                    materialOpacitySource = materialOpacityType,
                    materialColorSource = materialColorType,

                    hasVertexColor = hasVertexColor,
                    hasVertexOpacity = hasVertexOpacity,
                    needAlphaMultiplier = materialColorType != ShaderSourceAttribute.TEXTURE,
                )
            }

            is PhongMaterial -> {
                val albedoType = getSource(material.diffuseSource)
                val normalType = getSource(material.normalSource)
                val specularType = getSource(material.specularSource)

                val shinesType = getSource(material.shinesSource)
                val ambientType = getSource(material.ambientSource)
                val opacityType = getSource(material.opacitySource)

                val hasVertexColor = vertexAttributes.color == ColorFormat.BGR || vertexAttributes.color == ColorFormat.RGB
                val hasVertexOpacity = vertexAttributes.hasOpacity

                ShaderAttributes(
                    numLights = config.lightMaxAmount,
                    lightModel = config.lightModel,

                    materialOpacitySource = opacityType,
                    materialAlbedoSource = albedoType,
                    materialNormalSource = normalType,
                    materialSpecularSource = specularType,
                    materialShinesSource = shinesType,
                    materialAmbientSource = ambientType,

                    hasVertexColor = hasVertexColor,
                    hasVertexOpacity = hasVertexOpacity,
                    needAlphaMultiplier = albedoType != ShaderSourceAttribute.TEXTURE,
                )
            }

            is TileMapMaterial -> {
                ShaderAttributes(
                    numLights = config.lightMaxAmount,
                    lightModel = config.lightModel,

                    materialAlbedoSource = ShaderSourceAttribute.TEXTURE_ARRAY,
                    materialNormalSource = ShaderSourceAttribute.TEXTURE_ARRAY,
                    materialSpecularSource = ShaderSourceAttribute.TEXTURE_ARRAY,
                    hasMaterialTileMap = true,
                    hasMaterialTileGird = material.gird,
                )
            }

            else -> {
                ShaderAttributes()
            }
        }
    }

    private fun createSimpleShader(shaderAttributes: ShaderAttributes, config: OpenGlRendererConfig): ShaderController = shaderAttributes.run {
        logger.info { "createShader with $shaderAttributes" }

        val shaderDefines = mutableSetOf()

        appyDefine("MATERIAL_COLOR", materialColorSource, shaderDefines)
        appyDefine("MATERIAL_OPACITY", materialOpacitySource, shaderDefines)

        appyDefine("MATERIAL_ALBEDO", materialAlbedoSource, shaderDefines)
        appyDefine("MATERIAL_NORMAL", materialNormalSource, shaderDefines)
        appyDefine("MATERIAL_SPECULAR", materialSpecularSource, shaderDefines)
        appyDefine("MATERIAL_SHINES", materialShinesSource, shaderDefines)
        appyDefine("MATERIAL_AMBIENT", materialAmbientSource, shaderDefines)

        if (lightModel == ShaderLightModel.PHONG) {
            shaderDefines += "LIGHT_MODEL_PHONG"
        }
        if (lightModel == ShaderLightModel.BLINN_PHONG) {
            shaderDefines += "LIGHT_MODEL_BLINN_PHONG"
        }

        if (numLights > 0) {
            shaderDefines += "USE_LIGHTING"
            shaderDefines += "NUM_LIGHTS $numLights"
        }

        if (useTangentSpace) {
            shaderDefines += "USE_TANGENT_SPACE"
        }

        if (hasMaterialTileMap) {
            shaderDefines += "MATERIAL_TILE_MAP"
        }
        if (hasMaterialTileGird) {
            shaderDefines += "MATERIAL_TILE_GIRD"
        }
        if (hasVertexTextureCoord) {
            shaderDefines += "VERTEX_TEXTURE_COORD"
        }
        if (hasVertexColor) {
            shaderDefines += "VERTEX_COLOR"
        }
        if (hasVertexOpacity) {
            shaderDefines += "VERTEX_OPACITY"
        }
        if (needAlphaMultiplier) {
            shaderDefines += "NEED_ALPHA_MULTIPLIER"
        }
        if (config.alphaDiscard) {
            shaderDefines += "CONFIG_DISCARD_ALPHA"
        }
        if (config.lightGammaCorrection) {
            shaderDefines += "CONFIG_GAMMA_CORRECTION"
        }

        val vertexShader = ShaderFactory.setup(simpleShader.vertexShaderSource, shaderDefines)
        val fragmentShader = ShaderFactory.setup(simpleShader.fragmentShaderSource, shaderDefines)

        val buffer = ShaderBuffer(vertexShader, fragmentShader, null)
        return ShaderController(buffer, this)

    }

    private fun appyDefine(prefix: String, valueType: ShaderSourceAttribute?, target: MutableSet) {
        if (valueType == ShaderSourceAttribute.TEXTURE_ARRAY) {
            target += prefix + "_TEXTURE_ARRAY"
            target += prefix + "_ANY"
        } else if (valueType == ShaderSourceAttribute.TEXTURE) {
            target += prefix + "_TEXTURE"
            target += prefix + "_ANY"
        } else if (valueType == ShaderSourceAttribute.CONST) {
            target += prefix + "_CONST"
            target += prefix + "_ANY"
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy