[orx-compute-graph] Add compute graph code

This commit is contained in:
Edwin Jakobs
2022-01-09 10:51:21 +01:00
parent 9d08f859fa
commit 0858b8455c
11 changed files with 629 additions and 3 deletions

View File

@@ -0,0 +1,22 @@
# orx-compute-graph-nodes
A collection of nodes that can be used with orx-computer-graph.
## List of nodes
### Multi-platform
Name | Description | Inputs | Outputs
----------------|-----------------------|--------|---------
`filterNode` | Wrap around a `Filter`| | `image`
`fitImageNode` | Fit image to window bounds | `image` | `image`
### JVM only
Name | Description | Inputs | Outputs
----------------|-------------------|--------|---------
`drawCacheNode` | Cache drawing in an internal color buffer, commonly used as the final stage node | | `image`
`dropImageNode` | Listen for window file drop events | | `image`

View File

@@ -0,0 +1,97 @@
import EmbedShadersTask
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(project(":orx-parameters"))
implementation(project(":orx-shader-phrases"))
implementation(project(":orx-compute-graph"))
implementation(project(":orx-image-fit"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlinxSerializationVersion")
implementation("org.openrndr:openrndr-application:$openrndrVersion")
implementation("org.openrndr:openrndr-draw:$openrndrVersion")
implementation("org.openrndr:openrndr-filter:$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 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 jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}

View File

@@ -0,0 +1,27 @@
package org.openrndr.extra.computegraph.nodes
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.Filter
import org.openrndr.draw.createEquivalent
import org.openrndr.extra.computegraph.ComputeGraph
import org.openrndr.extra.computegraph.ComputeNode
import org.openrndr.extra.computegraph.withKey
fun <T : Filter> ComputeGraph.filterNode(
filter: T, input: ComputeNode, inputKey: String = "image", outputKey: String = "image",
config: ComputeNode.(f: Filter) -> Unit
): ComputeNode {
return node {
name = "filter-${filter::class.simpleName}"
inputs = filter.parameters
config(filter)
val inputImage by input.outputs.withKey<ColorBuffer>(inputKey)
var outputImage by outputs.withKey<ColorBuffer>(outputKey)
outputImage = inputImage.createEquivalent()
compute {
filter.apply(inputImage, outputImage)
}
dependOn(input)
}
}

View File

@@ -0,0 +1,29 @@
package org.openrndr.extra.computegraph.nodes
import org.openrndr.Program
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.isolatedWithTarget
import org.openrndr.draw.renderTarget
import org.openrndr.extra.computegraph.ComputeGraph
import org.openrndr.extra.computegraph.ComputeNode
import org.openrndr.extra.computegraph.withKey
import org.openrndr.extras.imageFit.imageFit
fun ComputeGraph.fitImageNode(program: Program, input: ComputeNode) : ComputeNode {
return node {
name = "fit-image"
val rt = renderTarget(program.width, program.height) {
colorBuffer()
}
val inputImage: ColorBuffer by input.outputs.withKey("image")
var outputImage:ColorBuffer by outputs.withKey("image")
outputImage = rt.colorBuffer(0)
compute {
program.drawer.isolatedWithTarget(rt) {
ortho(rt)
imageFit(inputImage, bounds)
}
}
dependOn(input)
}
}

View File

@@ -0,0 +1,99 @@
package org.openrndr.extra.computegraph.nodes
import mu.KotlinLogging
import org.openrndr.KEY_SPACEBAR
import org.openrndr.Program
import org.openrndr.RequestAssetsEvent
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.computegraph.ComputeGraph
import org.openrndr.extra.computegraph.ComputeNode
import org.openrndr.extra.computegraph.withKey
import java.io.File
val logger = KotlinLogging.logger { }
private data class RenderTargetDescription(val width: Int, val height: Int, val contentScale: Double)
private fun RenderTarget.description() = RenderTargetDescription(width, height, contentScale)
fun ComputeGraph.drawCacheNode(
program: Program,
inputNodes: List<ComputeNode>,
draw: Program.(node: ComputeNode) -> Unit
): ComputeNode {
return node {
var producingAssets: Boolean by inputs
producingAssets = false
program.keyboard.keyDown.listen {
if (!it.propagationCancelled) {
logger.info { "requesting assets" }
if (it.key == KEY_SPACEBAR) {
program.requestAssets.trigger(RequestAssetsEvent(this, program))
}
}
}
var screenshotTarget = ""
program.produceAssets.listen {
producingAssets = true
screenshotTarget = "screenshots/${it.assetMetadata.assetBaseName}.png"
}
name = "draw-cache"
var rt = renderTarget(program.width, program.height) {
colorBuffer()
depthBuffer()
}
var outputImage: ColorBuffer by outputs.withKey("image")
outputImage = rt.colorBuffer(0)
var description: RenderTargetDescription by inputs
description = RenderTarget.active.description()
update {
description = RenderTarget.active.description()
}
val defaultContentScale = program.window.contentScale
compute {
rt.colorBuffer(0).destroy()
rt.depthBuffer?.destroy()
rt.detachColorAttachments()
rt.detachDepthBuffer()
rt.destroy()
rt = renderTarget(
program.width,
program.height,
contentScale = if (producingAssets) 6.0 else defaultContentScale
) {
colorBuffer()
depthBuffer()
}
program.drawer.isolatedWithTarget(rt) {
clear(ColorRGBa.WHITE)
draw(program, this@node)
}
outputImage = rt.colorBuffer(0)
println(outputImage)
if (producingAssets) {
logger.info { "saving draw cache to file" }
val directory = File("screenshots")
if (!directory.exists()) {
directory.mkdirs()
}
outputImage.saveToFile(File(screenshotTarget), async = false)
producingAssets = false
screenshotTarget = ""
}
}
for (input in inputNodes) {
dependOn(input)
}
}
}

View File

@@ -0,0 +1,28 @@
package org.openrndr.extra.computegraph.nodes
import org.openrndr.Program
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.loadImage
import org.openrndr.extra.computegraph.ComputeGraph
import org.openrndr.extra.computegraph.ComputeNode
import java.io.File
fun ComputeGraph.dropImageNode(program: Program): ComputeNode {
return node {
name = "drop-image"
var file: File by inputs
file = File("data/images/cheeta.jpg")
program.window.drop.listen {
file = File(it.files.first())
}
var image: ColorBuffer by outputs
fun loadFileOrEmpty() = if (file.exists()) loadImage(file) else colorBuffer(256, 256)
image = loadFileOrEmpty()
compute {
image.destroy()
image = loadFileOrEmpty()
}
}
}