Add mask method to compositor

Closes #29
This commit is contained in:
Ricardo Matias
2020-03-05 16:10:07 +01:00
parent 8fe9596e91
commit 84b03f9ae5
3 changed files with 97 additions and 39 deletions

View File

@@ -5,40 +5,50 @@ A simple toolkit to make composite images.
##### Usage ##### Usage
```kotlin ```kotlin
import org.openrndr.Configuration
import org.openrndr.Program
import org.openrndr.application import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.draw.loadImage
import org.openrndr.extra.compositor.* import org.openrndr.extra.compositor.*
import org.openrndr.filter.blend.add import org.openrndr.extra.fx.blend.Add
import org.openrndr.filter.blur.ApproximateGaussianBlur import org.openrndr.extra.fx.edges.EdgesWork
import org.openrndr.extra.gui.GUI
import org.openrndr.math.Vector2
class Compositor001 : Program() {
override fun setup() { fun main() {
val drawing = compose { application {
draw { configure {
drawer.fill = ColorRGBa.PINK width = 768
drawer.circle(width / 2.0, height / 2.0, 10.0) height = 768
}
layer {
draw {
drawer.circle(width / 2.0, height / 2.0, 100.0)
}
post(ApproximateGaussianBlur()) {
window = 10
sigma = Math.cos(seconds * 10.0) * 10.0 + 10.0
}
blend(add)
}
} }
program {
val gui = GUI()
extend { val w2 = width / 2.0
drawing.draw(drawer) val h2 = height / 2.0
val c = compose {
draw {
drawer.fill = ColorRGBa.PINK
drawer.circle(width / 2.0, height / 2.0, 10.0)
}
layer {
blend(Add())
draw {
drawer.circle(width / 2.0, height / 2.0, 100.0)
}
post(ApproximateGaussianBlur()) {
window = 10
sigma = Math.cos(seconds * 10.0) * 10.0 + 10.0
}
}
}
extend(gui)
extend {
c.draw(drawer)
}
} }
} }
} }
fun main(args: Array<String>) = application(Compositor001(), Configuration())
``` ```

View File

@@ -1,3 +1,4 @@
dependencies { dependencies {
api project(":orx-parameters") api project(":orx-parameters")
api project(":orx-fx")
} }

View File

@@ -4,6 +4,10 @@ import org.openrndr.Extension
import org.openrndr.Program import org.openrndr.Program
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.extra.fx.blend.DestinationIn
import org.openrndr.extra.fx.blend.DestinationOut
import org.openrndr.extra.fx.blend.SourceIn
import org.openrndr.extra.fx.blend.SourceOut
import org.openrndr.extra.parameters.BooleanParameter import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.extra.parameters.Description import org.openrndr.extra.parameters.Description
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
@@ -27,6 +31,9 @@ fun RenderTarget.deepDestroy() {
*/ */
@Description("Layer") @Description("Layer")
open class Layer internal constructor() { open class Layer internal constructor() {
var sourceOut = SourceOut()
var destinationIn = SourceIn()
var maskLayer: Layer? = null
var drawFunc: () -> Unit = {} var drawFunc: () -> Unit = {}
val children: MutableList<Layer> = mutableListOf() val children: MutableList<Layer> = mutableListOf()
var blendFilter: Pair<Filter, Filter.() -> Unit>? = null var blendFilter: Pair<Filter, Filter.() -> Unit>? = null
@@ -36,6 +43,8 @@ open class Layer internal constructor() {
@BooleanParameter("enabled") @BooleanParameter("enabled")
var enabled = true var enabled = true
@BooleanParameter("Invert mask")
var invertMask = false
var clearColor: ColorRGBa? = ColorRGBa.TRANSPARENT var clearColor: ColorRGBa? = ColorRGBa.TRANSPARENT
private var layerTarget: RenderTarget? = null private var layerTarget: RenderTarget? = null
@@ -55,21 +64,27 @@ open class Layer internal constructor() {
null null
} }
val localLayerTarget = layerTarget if (shouldCreateLayerTarget(activeRenderTarget)) {
if (localLayerTarget == null || (localLayerTarget.width != activeRenderTarget.width || localLayerTarget.height != activeRenderTarget.height)) { createLayerTarget(activeRenderTarget, drawer)
layerTarget?.deepDestroy()
layerTarget = renderTarget(activeRenderTarget.width, activeRenderTarget.height) {
colorBuffer(type = colorType)
depthBuffer()
}
layerTarget?.let {
drawer.withTarget(it) {
drawer.background(ColorRGBa.TRANSPARENT)
}
}
} }
layerTarget?.let { target -> layerTarget?.let { target ->
maskLayer?.let {
if (it.shouldCreateLayerTarget(activeRenderTarget)) {
it.createLayerTarget(activeRenderTarget, drawer)
}
it.layerTarget?.let { maskRt ->
drawer.isolatedWithTarget(maskRt) {
clearColor?.let {
drawer.background(it)
}
it.drawFunc()
}
}
}
drawer.isolatedWithTarget(target) { drawer.isolatedWithTarget(target) {
clearColor?.let { clearColor?.let {
drawer.background(it) drawer.background(it)
@@ -109,6 +124,12 @@ open class Layer internal constructor() {
result result
} }
maskLayer?.let {
val maskFilter = if (invertMask) sourceOut else destinationIn
maskFilter.apply(arrayOf(it.layerTarget!!.colorBuffer(0), layerPost), layerPost)
}
val localBlendFilter = blendFilter val localBlendFilter = blendFilter
if (localBlendFilter == null) { if (localBlendFilter == null) {
drawer.isolatedWithTarget(activeRenderTarget) { drawer.isolatedWithTarget(activeRenderTarget) {
@@ -123,6 +144,23 @@ open class Layer internal constructor() {
} }
} }
} }
private fun shouldCreateLayerTarget(activeRenderTarget: RenderTarget): Boolean {
return layerTarget == null || (layerTarget?.width != activeRenderTarget.width || layerTarget?.height != activeRenderTarget.height)
}
private fun createLayerTarget(activeRenderTarget: RenderTarget, drawer: Drawer) {
layerTarget?.deepDestroy()
layerTarget = renderTarget(activeRenderTarget.width, activeRenderTarget.height) {
colorBuffer(type = colorType)
depthBuffer()
}
layerTarget?.let {
drawer.withTarget(it) {
drawer.background(ColorRGBa.TRANSPARENT)
}
}
}
} }
/** /**
@@ -141,6 +179,15 @@ fun Layer.draw(function: () -> Unit) {
drawFunc = function drawFunc = function
} }
/**
* the drawing acts as a mask on the layer
*/
fun Layer.mask(function: () -> Unit) {
maskLayer = Layer().apply {
this.drawFunc = function
}
}
/** /**
* add a post-processing filter to the layer * add a post-processing filter to the layer
*/ */