65 lines
2.9 KiB
Kotlin
65 lines
2.9 KiB
Kotlin
package org.openrndr.extra.shaderphrases
|
|
|
|
import org.openrndr.draw.codeFromURL
|
|
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
|
|
|
|
/**
|
|
* Preprocess shader source.
|
|
* Looks for "#pragma import" statements and injects found phrases.
|
|
* @param source GLSL source code encoded as string
|
|
* @return GLSL source code with injected shader phrases
|
|
*/
|
|
fun preprocessShader(source: String): String {
|
|
val lines = source.split("\n")
|
|
val processed = lines.mapIndexed { index, it ->
|
|
if (it.startsWith("#pragma import")) {
|
|
val tokens = it.split(" ")
|
|
val full = tokens[2]
|
|
val fullTokens = full.split(".")
|
|
val fieldName = fullTokens.last().replace(";", "").trim()
|
|
val packageClassTokens = fullTokens.dropLast(1)
|
|
val packageClass = packageClassTokens.joinToString(".")
|
|
|
|
try {
|
|
/* Note that JVM-style reflection is used here because of short-comings in the Kotlin reflection
|
|
library (as of 1.3.61), most notably reflection support for file facades is missing. */
|
|
val c = Class.forName(packageClass)
|
|
if (c.annotations.any { it.annotationClass == ShaderPhrases::class }) {
|
|
if (fieldName == "*") {
|
|
c.declaredMethods.filter { it.returnType.name == "java.lang.String" }.map {
|
|
"/* imported from $packageClass.$it */\n${it.invoke(null)}\n"
|
|
}.joinToString("\n") +
|
|
|
|
c.declaredFields.filter { it.type.name == "java.lang.String" }.map {
|
|
"/* imported from $packageClass.$it */\n${it.get(null)}\n"
|
|
}.joinToString("\n")
|
|
} else {
|
|
// TODO add method based phrase resolver like in the wildcard case above.
|
|
try {
|
|
c.getDeclaredField(fieldName).get(null)
|
|
} catch (e: NoSuchFieldException) {
|
|
error("field \"$fieldName\" not found in \"#pragma import $packageClass.$fieldName\" on line ${index + 1}")
|
|
}
|
|
}
|
|
} else {
|
|
throw IllegalArgumentException("class $packageClass has no ShaderPhrases annotation")
|
|
}
|
|
} catch (e: ClassNotFoundException) {
|
|
error("class \"$packageClass\" not found in \"#pragma import $packageClass\" on line ${index + 1}")
|
|
}
|
|
} else {
|
|
it
|
|
}
|
|
}
|
|
return processed.joinToString("\n")
|
|
}
|
|
|
|
/**
|
|
* Preprocess shader source from url
|
|
* Looks for "#pragma import" statements and injects found phrases.
|
|
* @param url url pointing to GLSL shader source
|
|
* @return GLSL source code with injected shader phrases
|
|
*/
|
|
fun preprocessShaderFromUrl(url: String): String {
|
|
return preprocessShader(codeFromURL(url))
|
|
} |