Add 'scriptless' mode to orx-olive

This commit is contained in:
Edwin Jakobs
2020-04-30 13:35:44 +02:00
parent 798ba9957d
commit e21e515ec2
16 changed files with 3637 additions and 14 deletions

View File

@@ -10,12 +10,14 @@ sourceSets {
dependencies {
implementation project(":orx-file-watcher")
implementation project(":orx-kotlin-parser")
implementation "org.jetbrains.kotlin:kotlin-scripting-jvm:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-scripting-jvm-host:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-scripting-jsr223:$kotlinVersion"
demoImplementation(project(":orx-camera"))
demoImplementation("org.openrndr:openrndr-core:$openrndrVersion")
demoImplementation("org.openrndr:openrndr-extensions:$openrndrVersion")

View File

@@ -0,0 +1,29 @@
import org.openrndr.Program
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.olive.Olive
import org.openrndr.math.IntVector2
fun main() {
application {
configure {
position = IntVector2(3440 / 2 + 200, 360)
width = 1280
height = 720
}
program {
extend(Olive<Program>()) {
script = "orx-olive/src/demo/kotlin/DemoOliveScriptless01.kt"
program {
extend {
drawer.background(ColorRGBa.PINK)
drawer.circle(width /2.0, height / 2.0, 300.0 + Math.cos(seconds)*100.0)
drawer.fill = ColorRGBa.RED
drawer.circle(mouse.position, 100.0)
}
}
}
}
}
}

View File

@@ -8,6 +8,7 @@ import org.openrndr.Program
import org.openrndr.draw.Session
import org.openrndr.events.Event
import org.openrndr.exceptions.stackRootClassName
import org.openrndr.extra.kotlinparser.extractProgram
import org.openrndr.launch
import org.operndr.extras.filewatcher.stop
import org.operndr.extras.filewatcher.triggerChange
@@ -34,7 +35,7 @@ enum class OliveScriptHost {
data class ScriptLoadedEvent(val scriptFile: String)
class Olive<P : Program>(val resources: Resources? = null) : Extension {
class Olive<P : Program>(val resources: Resources? = null, private var scriptless: Boolean = false) : Extension {
override var enabled: Boolean = true
var session: Session? = null
var scriptHost = OliveScriptHost.JSR223_REUSE
@@ -43,10 +44,12 @@ class Olive<P : Program>(val resources: Resources? = null) : Extension {
internal var scriptChange: (String) -> Unit = {}
var script = "src/main/kotlin/${stackRootClassName().split(".").last()}.kts"
var script = if (!scriptless) "src/main/kotlin/${stackRootClassName().split(".").last()}.kts"
else "src/main/kotlin/${stackRootClassName().split(".").last()}.kt"
set(value) {
field = value
scriptChange(value)
scriptless = value.endsWith(".kt")
}
/**
@@ -111,13 +114,21 @@ class Olive<P : Program>(val resources: Resources? = null) : Extension {
watcher = program.watchFile(File(script)) {
try {
logger.info("change detected, reloading script")
val scriptContents = if (!scriptless) {
it.readText()
} else {
val source = it.readText()
val programSource = extractProgram(source)
generateScript(programSource)
}
val futureFunc = GlobalScope.async {
val start = System.currentTimeMillis()
val loadedFunction = when (scriptHost) {
OliveScriptHost.JSR223_REUSE -> loadFromScript(it, jsr233ObjectLoader!!)
OliveScriptHost.JSR223 -> loadFromScript(it)
OliveScriptHost.KOTLIN_SCRIPT -> loadFromScriptKSH<P.() -> Unit>(it)
OliveScriptHost.JSR223_REUSE -> loadFromScriptContents(scriptContents, jsr233ObjectLoader!!)
OliveScriptHost.JSR223 -> loadFromScriptContents(scriptContents)
OliveScriptHost.KOTLIN_SCRIPT -> loadFromScriptContentsKSH<P.() -> Unit>(scriptContents)
}
val end = System.currentTimeMillis()
@@ -140,7 +151,6 @@ class Olive<P : Program>(val resources: Resources? = null) : Extension {
Unit
}
Unit
} catch (e: Throwable) {
e.printStackTrace()
}
@@ -170,4 +180,11 @@ class Olive<P : Program>(val resources: Resources? = null) : Extension {
}
}
}
fun program(f: Program.() -> Unit) {
require(script.endsWith(".kt")) {
"""program bodies are only allowed in 'scriptless' mode"""
}
}
}

View File

@@ -0,0 +1,17 @@
package org.openrndr.extra.olive
import org.openrndr.extra.kotlinparser.ProgramSource
fun generateScript(programSource: ProgramSource): String {
return """
@file:Suppress("UNUSED_LAMBDA_EXPRESSION")
${programSource.imports}
{ program: Program ->
program.apply {
${programSource.programLambda}
}
}
"""
}

View File

@@ -67,3 +67,10 @@ inline fun <reified T : Any> loadFromScript(fileOrUrl: String, loader: ScriptObj
*/
inline fun <reified T : Any> loadFromScript(file: File, loader: ScriptObjectLoader = ScriptObjectLoader()): T =
loader.load(file.readText())
/**
* Load an object from script file
*/
inline fun <reified T : Any> loadFromScriptContents(contents:String, loader: ScriptObjectLoader = ScriptObjectLoader()): T =
loader.load(contents)

View File

@@ -30,10 +30,10 @@ fun <T> loadFromScriptKSH(
}
}
): T = loadFromScriptKSH(script.readText(), host, body)
): T = loadFromScriptContentsKSH(script.readText(), host, body)
@Suppress("UNCHECKED_CAST")
fun <T> loadFromScriptKSH(
fun <T> loadFromScriptContentsKSH(
script: String,
host: BasicScriptingHost = BasicJvmScriptingHost(),
body: ScriptCompilationConfiguration.Builder.() -> Unit = {

View File

@@ -1,14 +1,12 @@
import org.amshove.kluent.`should be equal to`
import org.openrndr.extra.olive.ScriptObjectLoader
import org.openrndr.extra.olive.loadFromScript
import org.openrndr.extra.olive.loadFromScriptKSH
import org.openrndr.extra.olive.loadFromScriptContentsKSH
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
object TestLoadScriptKSH : Spek({
describe("some script") {
val number = loadFromScriptKSH<Int>("5")
val number = loadFromScriptContentsKSH<Int>("5")
it("should evaluate properly") {
number `should be equal to` 5