package me.eater.threedom.gl class ShaderPreProcessor { private val regex = Regex("(?[^:]+)::(?[^:(]+)\\((?.+)\\)") private val calls: MutableMap, (List) -> String> = mutableMapOf() fun process(input: String): String = input.split("\n").joinToString("\n") { if (it.startsWith("#[") && it.endsWith("]")) { val macro = it.substring(2 until it.length - 1) val match = regex.find(macro) ?: return@joinToString it val module = match.groups["module"]!!.value val call = match.groups["call"]!!.value val args = match.groups["args"]!!.value.split(",").map { arg -> arg.trim() }.toList() calls[module to call]?.invoke(args) ?: throw RuntimeException("Can't find macro $module::$call") } else { it } } fun register(module: String, call: String, block: (List) -> String) { calls[module to call] = block } fun compile(source: String, type: Shader.ShaderType): Shader { return Shader.create(process(source), type) } companion object { fun createDefault() = ShaderPreProcessor().apply { register("3dom", "import") { it -> val knownUniforms = mapOf( "model" to "mat4", "view" to "mat4", "projection" to "mat4", "normalModel" to "mat3" ) it.joinToString("\n") { uni -> "uniform ${knownUniforms[uni]} $uni;" } } } } }