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