diff --git a/orx-compositor/README.md b/orx-compositor/README.md index 8c469978..13bd0373 100644 --- a/orx-compositor/README.md +++ b/orx-compositor/README.md @@ -5,40 +5,50 @@ A simple toolkit to make composite images. ##### Usage ```kotlin -import org.openrndr.Configuration -import org.openrndr.Program import org.openrndr.application -import org.openrndr.color.ColorRGBa +import org.openrndr.draw.loadImage import org.openrndr.extra.compositor.* -import org.openrndr.filter.blend.add -import org.openrndr.filter.blur.ApproximateGaussianBlur +import org.openrndr.extra.fx.blend.Add +import org.openrndr.extra.fx.edges.EdgesWork +import org.openrndr.extra.gui.GUI +import org.openrndr.math.Vector2 -class Compositor001 : Program() { - override fun setup() { - val drawing = compose { - draw { - drawer.fill = ColorRGBa.PINK - drawer.circle(width / 2.0, height / 2.0, 10.0) - } - - 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) - } +fun main() { + application { + configure { + width = 768 + height = 768 } + program { + val gui = GUI() - extend { - drawing.draw(drawer) + val w2 = width / 2.0 + 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) = application(Compositor001(), Configuration()) ``` diff --git a/orx-compositor/build.gradle b/orx-compositor/build.gradle index 7afc9b60..7ab63df0 100644 --- a/orx-compositor/build.gradle +++ b/orx-compositor/build.gradle @@ -1,3 +1,4 @@ dependencies { api project(":orx-parameters") + api project(":orx-fx") } \ No newline at end of file diff --git a/orx-compositor/src/main/kotlin/Compositor.kt b/orx-compositor/src/main/kotlin/Compositor.kt index dd675701..d0b0d9af 100644 --- a/orx-compositor/src/main/kotlin/Compositor.kt +++ b/orx-compositor/src/main/kotlin/Compositor.kt @@ -4,6 +4,10 @@ import org.openrndr.Extension import org.openrndr.Program import org.openrndr.color.ColorRGBa 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.Description import org.openrndr.math.Matrix44 @@ -27,6 +31,9 @@ fun RenderTarget.deepDestroy() { */ @Description("Layer") open class Layer internal constructor() { + var sourceOut = SourceOut() + var destinationIn = SourceIn() + var maskLayer: Layer? = null var drawFunc: () -> Unit = {} val children: MutableList = mutableListOf() var blendFilter: Pair Unit>? = null @@ -36,6 +43,8 @@ open class Layer internal constructor() { @BooleanParameter("enabled") var enabled = true + @BooleanParameter("Invert mask") + var invertMask = false var clearColor: ColorRGBa? = ColorRGBa.TRANSPARENT private var layerTarget: RenderTarget? = null @@ -55,21 +64,27 @@ open class Layer internal constructor() { null } - val localLayerTarget = layerTarget - if (localLayerTarget == null || (localLayerTarget.width != activeRenderTarget.width || localLayerTarget.height != activeRenderTarget.height)) { - layerTarget?.deepDestroy() - layerTarget = renderTarget(activeRenderTarget.width, activeRenderTarget.height) { - colorBuffer(type = colorType) - depthBuffer() - } - layerTarget?.let { - drawer.withTarget(it) { - drawer.background(ColorRGBa.TRANSPARENT) - } - } + if (shouldCreateLayerTarget(activeRenderTarget)) { + createLayerTarget(activeRenderTarget, drawer) } 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) { clearColor?.let { drawer.background(it) @@ -109,6 +124,12 @@ open class Layer internal constructor() { result } + maskLayer?.let { + val maskFilter = if (invertMask) sourceOut else destinationIn + + maskFilter.apply(arrayOf(it.layerTarget!!.colorBuffer(0), layerPost), layerPost) + } + val localBlendFilter = blendFilter if (localBlendFilter == null) { 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 } +/** + * 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 */