Convert orx-shader-phrases and orx-noise to MPP
This commit is contained in:
99
orx-shader-phrases/build.gradle.kts
Normal file
99
orx-shader-phrases/build.gradle.kts
Normal file
@@ -0,0 +1,99 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
val kotlinxSerializationVersion: String by rootProject.extra
|
||||
val kotestVersion: String by rootProject.extra
|
||||
val junitJupiterVersion: String by rootProject.extra
|
||||
val jvmTarget: String by rootProject.extra
|
||||
val kotlinApiVersion: String by rootProject.extra
|
||||
val kotlinVersion: String by rootProject.extra
|
||||
val kotlinLoggingVersion: String by rootProject.extra
|
||||
val kluentVersion: String by rootProject.extra
|
||||
val openrndrVersion: String by rootProject.extra
|
||||
val openrndrOS: String by rootProject.extra
|
||||
val spekVersion: String by rootProject.extra
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations {
|
||||
val demo by creating {
|
||||
defaultSourceSet {
|
||||
kotlin.srcDir("src/demo")
|
||||
dependencies {
|
||||
implementation(project(":orx-camera"))
|
||||
implementation("org.openrndr:openrndr-application:$openrndrVersion")
|
||||
implementation("org.openrndr:openrndr-extensions:$openrndrVersion")
|
||||
runtimeOnly("org.openrndr:openrndr-gl3:$openrndrVersion")
|
||||
runtimeOnly("org.openrndr:openrndr-gl3-natives-$openrndrOS:$openrndrVersion")
|
||||
implementation(compilations["main"]!!.output.allOutputs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
compilations.all {
|
||||
kotlinOptions.jvmTarget = jvmTarget
|
||||
kotlinOptions.apiVersion = kotlinApiVersion
|
||||
}
|
||||
testRuns["test"].executionTask.configure {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
js(IR) {
|
||||
browser()
|
||||
nodejs()
|
||||
}
|
||||
|
||||
|
||||
sourceSets {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlinxSerializationVersion")
|
||||
implementation("org.openrndr:openrndr-application:$openrndrVersion")
|
||||
implementation("org.openrndr:openrndr-draw:$openrndrVersion")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
|
||||
implementation("io.github.microutils:kotlin-logging:$kotlinLoggingVersion")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-common"))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
|
||||
implementation("io.kotest:kotest-assertions-core:$kotestVersion")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val jvmMain by getting
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-common"))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation(kotlin("test-junit5"))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
|
||||
runtimeOnly("org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion")
|
||||
runtimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion")
|
||||
implementation("org.spekframework.spek2:spek-dsl-jvm:$spekVersion")
|
||||
implementation("org.amshove.kluent:kluent:$kluentVersion")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val jsMain by getting
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val jsTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-js"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
orx-shader-phrases/src/commonMain/kotlin/ShaderPreprocessor.kt
Normal file
127
orx-shader-phrases/src/commonMain/kotlin/ShaderPreprocessor.kt
Normal file
@@ -0,0 +1,127 @@
|
||||
package org.openrndr.extra.shaderphrases
|
||||
|
||||
import mu.KotlinLogging
|
||||
import org.openrndr.draw.Shader
|
||||
import org.openrndr.utils.url.textFromURL
|
||||
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* A single shader phrase.
|
||||
*/
|
||||
class ShaderPhrase(val phrase: String) {
|
||||
/**
|
||||
* Register this shader phrase in the [ShaderPhraseRegistry]
|
||||
* This will likely be called by [ShaderPhraseBook]
|
||||
*/
|
||||
fun register(bookId: String? = null) {
|
||||
val functionRex =
|
||||
Regex("(float|int|[bi]?vec2|[bi]?vec3|[bi]?vec4|mat3|mat4)[ ]+([a-zA-Z0-9_]+)[ ]*\\(.*\\).*")
|
||||
val defs = phrase.split("\n").filter {
|
||||
functionRex.matches(it)
|
||||
}.take(1).mapNotNull {
|
||||
val m = functionRex.find(it)
|
||||
m?.groupValues?.getOrNull(2)
|
||||
}
|
||||
val id = defs.firstOrNull() ?: error("no function body found in phrase")
|
||||
ShaderPhraseRegistry.registerPhrase("${bookId?.let { "$it." } ?: ""}$id", this)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A book of shader phrases.
|
||||
*/
|
||||
expect open class ShaderPhraseBook(bookId: String) {
|
||||
//private var registered = false
|
||||
/**
|
||||
* Registers all known shader phrases
|
||||
*/
|
||||
fun register()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The global, application-wide, shader phrase registry
|
||||
*/
|
||||
object ShaderPhraseRegistry {
|
||||
private val phrases = mutableMapOf<String, ShaderPhrase>()
|
||||
/**
|
||||
* Registers a [phrase] with [id]
|
||||
*/
|
||||
fun registerPhrase(id: String, phrase: ShaderPhrase) {
|
||||
phrases[id] = phrase
|
||||
}
|
||||
/**
|
||||
* Finds a phrase for [id], returns null when no phrase found
|
||||
*/
|
||||
fun findPhrase(id: String): ShaderPhrase? {
|
||||
val phrase = phrases[id]
|
||||
if (phrase == null) {
|
||||
logger.warn { "no phrase found for id: \"$id\"" }
|
||||
}
|
||||
return phrase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, symbols: Set<String> = emptySet()): String {
|
||||
val newSymbols = mutableSetOf<String>()
|
||||
newSymbols.addAll(symbols)
|
||||
|
||||
val lines = source.split("\n")
|
||||
val processed = lines.mapIndexed { index, it ->
|
||||
if (it.startsWith("#pragma import")) {
|
||||
val tokens = it.split(" ")
|
||||
val symbol = tokens[2].trim().replace(";", "")
|
||||
val fullTokens = symbol.split(".")
|
||||
val fieldName = fullTokens.last().replace(";", "").trim()
|
||||
val packageClassTokens = fullTokens.dropLast(1)
|
||||
val packageClass = packageClassTokens.joinToString(".")
|
||||
if (symbol !in newSymbols) {
|
||||
newSymbols.add(symbol)
|
||||
val registryPhrase = ShaderPhraseRegistry.findPhrase(symbol)
|
||||
registryPhrase?.let { preprocessShader(it.phrase, newSymbols) }
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
return processed.joinToString("\n")
|
||||
}
|
||||
|
||||
fun String.preprocess() = preprocessShader(this)
|
||||
|
||||
/**
|
||||
* 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, symbols: Set<String> = emptySet()): String {
|
||||
return preprocessShader(textFromURL(url), symbols)
|
||||
}
|
||||
|
||||
fun Shader.Companion.preprocessedFromUrls(
|
||||
vsUrl: String,
|
||||
tcsUrl: String? = null,
|
||||
tesUrl: String? = null,
|
||||
gsUrl: String? = null,
|
||||
fsUrl: String
|
||||
): Shader {
|
||||
|
||||
val vsCode = textFromURL(vsUrl).preprocess()
|
||||
val tcsCode = tcsUrl?.let { textFromURL(it) }?.preprocess()
|
||||
val tesCode = tesUrl?.let { textFromURL(it) }?.preprocess()
|
||||
val gsCode = gsUrl?.let { textFromURL(it) }?.preprocess()
|
||||
val fsCode = textFromURL(fsUrl).preprocess()
|
||||
val name = "$$vsUrl / $gsUrl / $fsUrl"
|
||||
return Shader.createFromCode(vsCode, tcsCode, tesCode, gsCode, fsCode, name)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.openrndr.extra.shaderphrases.phrases
|
||||
|
||||
val phraseTbnMatrix = """"""
|
||||
15
orx-shader-phrases/src/jsMain/kotlin/ShaderPhraseBook.kt
Normal file
15
orx-shader-phrases/src/jsMain/kotlin/ShaderPhraseBook.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package org.openrndr.extra.shaderphrases
|
||||
|
||||
/**
|
||||
* A book of shader phrases.
|
||||
*/
|
||||
actual open class ShaderPhraseBook actual constructor(val bookId: String) {
|
||||
private var registered = false
|
||||
/**
|
||||
* Registers all known shader phrases
|
||||
*/
|
||||
actual fun register() {
|
||||
error("not supported")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,4 +21,4 @@ class PhraseResource<R>(private val resourceUrl: String) : ReadOnlyProperty<R, S
|
||||
*/
|
||||
fun phraseResource(resource: String) : PhraseResource<Any?> {
|
||||
return PhraseResource(resourceUrl(resource))
|
||||
}
|
||||
}
|
||||
26
orx-shader-phrases/src/jvmMain/kotlin/ShaderPhraseBook.kt
Normal file
26
orx-shader-phrases/src/jvmMain/kotlin/ShaderPhraseBook.kt
Normal file
@@ -0,0 +1,26 @@
|
||||
package org.openrndr.extra.shaderphrases
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
|
||||
/**
|
||||
* A book of shader phrases.
|
||||
*/
|
||||
actual open class ShaderPhraseBook actual constructor(val bookId: String) {
|
||||
private var registered = false
|
||||
/**
|
||||
* Registers all known shader phrases
|
||||
*/
|
||||
actual fun register() {
|
||||
if (!registered) {
|
||||
this::class.declaredMemberProperties.filter {
|
||||
it.returnType.toString() == "org.openrndr.extra.shaderphrases.ShaderPhrase"
|
||||
}.map {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val m = it as? KProperty1<ShaderPhraseBook, ShaderPhrase>
|
||||
m?.get(this)?.register(bookId)
|
||||
}
|
||||
registered = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
package org.openrndr.extra.shaderphrases
|
||||
|
||||
import mu.KotlinLogging
|
||||
import org.openrndr.draw.Shader
|
||||
import org.openrndr.draw.codeFromURL
|
||||
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* A single shader phrase.
|
||||
*/
|
||||
class ShaderPhrase(val phrase: String) {
|
||||
/**
|
||||
* Register this shader phrase in the [ShaderPhraseRegistry]
|
||||
* This will likely be called by [ShaderPhraseBook]
|
||||
*/
|
||||
fun register(bookId: String? = null) {
|
||||
val functionRex =
|
||||
Regex("(float|int|[bi]?vec2|[bi]?vec3|[bi]?vec4|mat3|mat4)[ ]+([a-zA-Z0-9_]+)[ ]*\\(.*\\).*")
|
||||
val defs = phrase.split("\n").filter {
|
||||
functionRex.matches(it)
|
||||
}.take(1).mapNotNull {
|
||||
val m = functionRex.find(it)
|
||||
m?.groupValues?.getOrNull(2)
|
||||
}
|
||||
val id = defs.firstOrNull() ?: error("no function body found in phrase")
|
||||
ShaderPhraseRegistry.registerPhrase("${bookId?.let { "$it." } ?: ""}$id", this)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A book of shader phrases.
|
||||
*/
|
||||
open class ShaderPhraseBook(val bookId: String) {
|
||||
private var registered = false
|
||||
|
||||
/**
|
||||
* Registers all known shader phrases
|
||||
*/
|
||||
fun register() {
|
||||
if (!registered) {
|
||||
this::class.declaredMemberProperties.filter {
|
||||
it.returnType.toString() == "org.openrndr.extra.shaderphrases.ShaderPhrase"
|
||||
}.map {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val m = it as? KProperty1<ShaderPhraseBook, ShaderPhrase>
|
||||
m?.get(this)?.register(bookId)
|
||||
}
|
||||
registered = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The global, application-wide, shader phrase registry
|
||||
*/
|
||||
object ShaderPhraseRegistry {
|
||||
private val phrases = mutableMapOf<String, ShaderPhrase>()
|
||||
/**
|
||||
* Registers a [phrase] with [id]
|
||||
*/
|
||||
fun registerPhrase(id: String, phrase: ShaderPhrase) {
|
||||
phrases[id] = phrase
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a phrase for [id], returns null when no phrase found
|
||||
*/
|
||||
fun findPhrase(id: String): ShaderPhrase? {
|
||||
val phrase = phrases[id]
|
||||
if (phrase == null) {
|
||||
logger.warn { "no phrase found for id: \"$id\"" }
|
||||
}
|
||||
return phrase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, symbols: Set<String> = emptySet()): String {
|
||||
val newSymbols = mutableSetOf<String>()
|
||||
newSymbols.addAll(symbols)
|
||||
|
||||
val lines = source.split("\n")
|
||||
val processed = lines.mapIndexed { index, it ->
|
||||
if (it.startsWith("#pragma import")) {
|
||||
val tokens = it.split(" ")
|
||||
val symbol = tokens[2].trim().replace(";", "")
|
||||
val fullTokens = symbol.split(".")
|
||||
val fieldName = fullTokens.last().replace(";", "").trim()
|
||||
val packageClassTokens = fullTokens.dropLast(1)
|
||||
val packageClass = packageClassTokens.joinToString(".")
|
||||
|
||||
if (symbol !in newSymbols) {
|
||||
newSymbols.add(symbol)
|
||||
val registryPhrase = ShaderPhraseRegistry.findPhrase(symbol)
|
||||
|
||||
registryPhrase?.let { preprocessShader(it.phrase, newSymbols) }
|
||||
?: 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 {
|
||||
var result: String?
|
||||
try {
|
||||
val methodName = "get${fieldName.take(1).toUpperCase() + fieldName.drop(1)}"
|
||||
result =
|
||||
preprocessShader(c.getMethod(methodName).invoke(null) as String, newSymbols)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
try {
|
||||
result =
|
||||
preprocessShader(
|
||||
c.getDeclaredField(fieldName).get(null) as String,
|
||||
newSymbols
|
||||
)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
println(source)
|
||||
error("field \"$fieldName\" not found in \"#pragma import $packageClass.$fieldName\" on line ${index + 1}")
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
} else {
|
||||
throw IllegalArgumentException("class $packageClass has no ShaderPhrases annotation")
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
println(source)
|
||||
error("class \"$packageClass\" not found in \"#pragma import $packageClass\" on line ${index + 1}")
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
return processed.joinToString("\n")
|
||||
}
|
||||
|
||||
fun String.preprocess() = preprocessShader(this)
|
||||
|
||||
|
||||
/**
|
||||
* 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, symbols: Set<String> = emptySet()): String {
|
||||
return preprocessShader(codeFromURL(url), symbols)
|
||||
}
|
||||
|
||||
fun Shader.Companion.preprocessedFromUrls(
|
||||
vsUrl: String,
|
||||
tcsUrl: String? = null,
|
||||
tesUrl: String? = null,
|
||||
gsUrl: String? = null,
|
||||
fsUrl: String
|
||||
): Shader {
|
||||
|
||||
val vsCode = codeFromURL(vsUrl).preprocess()
|
||||
val tcsCode = tcsUrl?.let { codeFromURL(it) }?.preprocess()
|
||||
val tesCode = tesUrl?.let { codeFromURL(it) }?.preprocess()
|
||||
val gsCode = gsUrl?.let { codeFromURL(it) }?.preprocess()
|
||||
val fsCode = codeFromURL(fsUrl).preprocess()
|
||||
val name = "$$vsUrl / $gsUrl / $fsUrl"
|
||||
return Shader.createFromCode(vsCode, tcsCode, tesCode, gsCode, fsCode, name)
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.openrndr.extra.shaderphrases.annotations
|
||||
|
||||
enum class ShaderPhraseLanguage {
|
||||
GLSL_330
|
||||
}
|
||||
|
||||
@Target(AnnotationTarget.FILE)
|
||||
annotation class ShaderPhrases(val exports: Array<String> = emptyArray())
|
||||
@@ -1,42 +0,0 @@
|
||||
@file:JvmName("Depth")
|
||||
@file:ShaderPhrases([])
|
||||
package org.openrndr.extra.shaderphrases.phrases
|
||||
|
||||
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
|
||||
|
||||
|
||||
/**
|
||||
* phrase for conversion from view to projection depth
|
||||
* @param viewDepth depth in view space ([0.0 .. -far])
|
||||
* @param projection projection matrix
|
||||
* @return depth in projection space ([0.0 .. 1.0]]
|
||||
*/
|
||||
const val viewToProjectionDepth = """
|
||||
float viewToProjectionDepth(float viewDepth, mat4 projection) {
|
||||
float z = viewDepth * projection[2].z + projection[3].z;
|
||||
float w = viewDepth * projection[2].w + projection[3].w;
|
||||
return z / w;
|
||||
}
|
||||
"""
|
||||
|
||||
/**
|
||||
* phrase for conversion from projection to view depth
|
||||
* @param projectionDepth depth in projection space ([0.0 .. 1.0])
|
||||
* @param projectionInversed inverse of the projection matrix
|
||||
* @return depth in view space ([0.0 .. -far]]
|
||||
*/
|
||||
const val projectionToViewDepth = """
|
||||
float projectionToViewDepth(float projectionDepth, mat4 projectionInverse) {
|
||||
float z = (projectionDepth*2.0-1.0) * projectionInverse[2].z + projectionInverse[3].z;
|
||||
float w = (projectionDepth*2.0-1.0) * projectionInverse[2].w + projectionInverse[3].w;
|
||||
return z / w;
|
||||
}
|
||||
"""
|
||||
|
||||
const val projectionToViewCoordinate = """
|
||||
vec3 projectionToViewCoordinate(vec2 uv, float projectionDepth, mat4 projectionInverse) {
|
||||
vec4 projectionCoordinate = vec4(uv * 2.0 - 1.0, projectionDepth*2.0-1.0, 1.0);
|
||||
vec4 viewCoordinate = projectionInverse * projectionCoordinate;
|
||||
return viewCoordinate.xyz / viewCoordinate.w;
|
||||
}
|
||||
"""
|
||||
@@ -1,21 +0,0 @@
|
||||
@file:JvmName("Dummy")
|
||||
@file:ShaderPhrases
|
||||
|
||||
package org.openrndr.extra.shaderphrases.phrases
|
||||
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
|
||||
import org.openrndr.extra.shaderphrases.preprocessShader
|
||||
|
||||
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))
|
||||
}
|
||||
println(preprocessShader("import org.openrndr.extra.shaderphrases.phrases.Dummy.*"))
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
@file:JvmName("NormalMapping")
|
||||
@file:ShaderPhrases
|
||||
|
||||
package org.openrndr.extra.shaderphrases.phrases
|
||||
|
||||
import org.openrndr.extra.shaderphrases.annotations.ShaderPhrases
|
||||
|
||||
val phraseTbnMatrix = """
|
||||
mat3 tbnMatrix(vec4 tangent, vec3 normal) {
|
||||
vec3 bitangent = cross(normal, tangent.xyz) * tangent.w;
|
||||
return mat3(tangent.xyz, bitangent, normal);
|
||||
}
|
||||
""".trimIndent()
|
||||
@@ -1,53 +0,0 @@
|
||||
import org.amshove.kluent.`should contain`
|
||||
import org.amshove.kluent.`should throw`
|
||||
import org.amshove.kluent.`with message`
|
||||
import org.amshove.kluent.invoking
|
||||
import org.openrndr.extra.shaderphrases.preprocessShader
|
||||
import org.openrndr.extra.shaderphrases.preprocessShaderFromUrl
|
||||
import org.openrndr.resourceUrl
|
||||
import org.spekframework.spek2.Spek
|
||||
import org.spekframework.spek2.style.specification.describe
|
||||
|
||||
object TestPreprocessShader : Spek({
|
||||
describe("An url pointing to a shader resource") {
|
||||
val url = resourceUrl("/from-url-test.frag")
|
||||
describe("results in injected dummy phrase when preprocessed") {
|
||||
val processed = preprocessShaderFromUrl(url)
|
||||
processed `should contain` "float dummy"
|
||||
}
|
||||
}
|
||||
|
||||
describe("A shader with import statements") {
|
||||
val shader = """
|
||||
|#version 330
|
||||
|#pragma import org.openrndr.extra.shaderphrases.phrases.Dummy.*""".trimMargin()
|
||||
describe("injects dummy phrase when preprocessed") {
|
||||
val processed = preprocessShader(shader)
|
||||
processed `should contain` "float dummy"
|
||||
}
|
||||
}
|
||||
|
||||
describe("A shader with non-resolvable class statements") {
|
||||
val shader = """#version 330
|
||||
#pragma import invalid.Class.*
|
||||
"""
|
||||
describe("throws exception when preprocessed") {
|
||||
invoking {
|
||||
preprocessShader(shader)
|
||||
} `should throw` RuntimeException::class `with message`
|
||||
("class \"invalid.Class\" not found in \"#pragma import invalid.Class\" on line 2")
|
||||
}
|
||||
}
|
||||
|
||||
describe("A shader with non-resolvable property statements") {
|
||||
val shader = """#version 330
|
||||
#pragma import org.openrndr.extra.shaderphrases.phrases.Dummy.invalid
|
||||
"""
|
||||
describe("throws exception when preprocessed") {
|
||||
invoking {
|
||||
preprocessShader(shader)
|
||||
} `should throw` RuntimeException::class `with message`
|
||||
("field \"invalid\" not found in \"#pragma import org.openrndr.extra.shaderphrases.phrases.Dummy.invalid\" on line 2")
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user