Added WIP shader-phrases, annotations and tooling for shader phrases

resolving is done using the JVM class loader
This commit is contained in:
Edwin Jakobs
2019-08-23 16:46:24 +02:00
parent 3c162f30d4
commit 98baf2a4c3
8 changed files with 134 additions and 7 deletions

View File

@@ -10,7 +10,7 @@ buildscript {
plugins {
// plugin dependencies, load without applying them
id 'nebula.kotlin' version '1.3.41' apply false
id 'nebula.kotlin' version '1.3.50' apply false
id 'com.jfrog.artifactory' version '4.6.2' apply false
id 'nebula.contacts' version '4.1.1' apply false
@@ -38,7 +38,7 @@ plugins {
project.ext {
openrndrVersion = "0.3.35"
kotlinVersion = "1.3.41"
kotlinVersion = "1.3.50"
spekVersion = "2.0.6"
}
@@ -65,16 +65,14 @@ allprojects {
repositories {
mavenCentral()
jcenter()
maven {
url = "https://dl.bintray.com/openrndr/openrndr"
}
maven {
url "https://dl.bintray.com/spekframework/spek"
}
}
dependencies {
@@ -82,11 +80,12 @@ allprojects {
compile "org.openrndr:openrndr-filter:$openrndrVersion"
compile "org.openrndr:openrndr-shape:$openrndrVersion"
compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.3.0-RC2'
testImplementation "org.spekframework.spek2:spek-dsl-jvm:$spekVersion"
testImplementation "org.amshove.kluent:kluent:1.53"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion"
testRuntimeOnly "org.spekframework.spek2:spek-runner-junit5:$spekVersion"
testRuntimeOnly "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
runtime "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
}
contacts {

3
orx-noise/build.gradle Normal file
View File

@@ -0,0 +1,3 @@
dependencies {
implementation project(":orx-shader-phrases")
}

View File

@@ -0,0 +1,32 @@
@file:ShaderPhrases(exports = ["hash22","hash21","valueNoise21"])
package org.openrndr.extra.noise.phrases
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrase
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
@ShaderPhrase(exports = ["hash22"])
val phraseHash22 = """vec2 hash22(vec2 p) {
float n = sin(dot(p, vec2(41, 289)));
return fract(vec2(262144, 32768)*n);
}
"""
@ShaderPhrase(exports = ["hash21"])
val phraseHash21 = "float hash21(vec2 p) { return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x)))); }"
@ShaderPhrase(exports = ["valueNoise21"], imports = ["hash21"])
val phraseValueNoise21 = """
float noise(vec2 x) {
vec2 i = floor(x);
vec2 f = fract(x);
float a = hash21(i);
float b = hash21(i + vec2(1.0, 0.0));
float c = hash21(i + vec2(0.0, 1.0));
float d = hash21(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
""".trimIndent()

View File

@@ -0,0 +1,33 @@
package org.openrndr.extra.shaderphrases
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
fun preprocessShader(shader: String): String {
val lines = shader.split("\n")
val processed = lines.map {
if (it.startsWith("import ")) {
val tokens = it.split(" ")
val full = tokens[1]
val fullTokens = full.split(".")
val fieldName = fullTokens.last().replace(";","")
val packageClassTokens = fullTokens.dropLast(1)
val packageClass = packageClassTokens.joinToString(".")
val c = Class.forName(packageClass)
if (c.annotations.any { it.annotationClass == ShaderPhrases::class }) {
if (fieldName == "*") {
c.declaredFields.filter { println(it.type); it.type.name =="java.lang.String" }.map {
it.get(null)
}.joinToString("\n")
} else {
c.getDeclaredField(fieldName).get(null)
}
} else {
throw IllegalArgumentException("class $packageClass has no ShaderPhrases annotation")
}
} else {
it
}
}
return processed.joinToString("\n")
}

View File

@@ -0,0 +1,15 @@
package org.openrndr.extra.shaderphrases.annotations
enum class ShaderPhraseLanguage {
GLSL
}
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FILE, AnnotationTarget.CLASS, AnnotationTarget.FIELD)
annotation class ShaderPhrase(val exports: Array<String>,
val imports: Array<String> = emptyArray(),
val language: ShaderPhraseLanguage = ShaderPhraseLanguage.GLSL)
@Target(AnnotationTarget.FILE)
annotation class ShaderPhrases(val exports: Array<String>)

View File

@@ -0,0 +1,24 @@
@file:JvmName("Dummy")
@file:ShaderPhrases(["dummy"])
package org.openrndr.extra.shaderphrases.phrases
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrase
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
@ShaderPhrase(["dummy"])
const val phraseDummy = """
float dummy() {
return 0.0;
}
"""
fun main() {
val c = Class.forName("org.openrndr.extra.shaderphrases.phrases.Dummy")
if (c.annotations.any { it.annotationClass == ShaderPhrases::class }) {
println(c.getDeclaredField("phraseDummy").get(null))
}
}

View File

@@ -0,0 +1,19 @@
import org.openrndr.extra.shaderphrases.preprocessShader
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
object TestPreprocessShader:Spek({
describe("A shader with import statements") {
val shader = """
#version 330
import org.openrndr.extra.shaderphrases.phrases.Dummy.*
""".trimIndent()
describe("when preprocessed") {
val processed = preprocessShader(shader)
println(processed)
}
}
})

View File

@@ -14,4 +14,6 @@ include 'orx-camera',
'orx-no-clear',
'orx-noise',
'orx-obj-loader',
'orx-olive'
'orx-olive',
'orx-shader-phrases',
'orx-shader-phrases-processor'