diff --git a/orx-compositor/src/main/kotlin/Compositor.kt b/orx-compositor/src/main/kotlin/Compositor.kt index 6b79b847..83ace9e7 100644 --- a/orx-compositor/src/main/kotlin/Compositor.kt +++ b/orx-compositor/src/main/kotlin/Compositor.kt @@ -4,6 +4,7 @@ import org.openrndr.Extension import org.openrndr.Program import org.openrndr.color.ColorRGBa import org.openrndr.draw.* +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 @@ -29,8 +30,9 @@ fun RenderTarget.deepDestroy() { */ @Description("Layer") open class Layer internal constructor() { + var copyLayers: List = listOf() var sourceOut = SourceOut() - var destinationIn = SourceIn() + var sourceIn = SourceIn() var maskLayer: Layer? = null var drawFunc: () -> Unit = {} val children: MutableList = mutableListOf() @@ -46,6 +48,11 @@ open class Layer internal constructor() { var clearColor: ColorRGBa? = ColorRGBa.TRANSPARENT private var layerTarget: RenderTarget? = null + val result: ColorBuffer? + get() { + return layerTarget?.colorBuffer(0) + } + /** * draw the layer */ @@ -67,6 +74,20 @@ open class Layer internal constructor() { } layerTarget?.let { target -> + if (copyLayers.isNotEmpty()) { + copyLayers.forEach { + drawer.isolatedWithTarget(target) { + clearColor?.let { + drawer.background(it) + } + + it.layerTarget?.let { copyTarget -> + drawer.image(copyTarget.colorBuffer(0)) + } + } + } + } + maskLayer?.let { if (it.shouldCreateLayerTarget(activeRenderTarget)) { it.createLayerTarget(activeRenderTarget, drawer) @@ -74,18 +95,23 @@ open class Layer internal constructor() { it.layerTarget?.let { maskRt -> drawer.isolatedWithTarget(maskRt) { - clearColor?.let { - drawer.background(it) + if (copyLayers.isEmpty()) { + clearColor?.let { color -> + drawer.background(color) + } } - + drawer.fill = ColorRGBa.WHITE + drawer.stroke = ColorRGBa.WHITE it.drawFunc() } } } drawer.isolatedWithTarget(target) { - clearColor?.let { - drawer.background(it) + if (copyLayers.isEmpty()) { + clearColor?.let { + drawer.background(it) + } } drawFunc() children.forEach { @@ -123,9 +149,9 @@ open class Layer internal constructor() { } maskLayer?.let { - val maskFilter = if (invertMask) sourceOut else destinationIn + val maskFilter = if (invertMask) sourceOut else sourceIn - maskFilter.apply(arrayOf(it.layerTarget!!.colorBuffer(0), layerPost), layerPost) + maskFilter.apply(arrayOf(layerPost, it.layerTarget!!.colorBuffer(0)), layerPost) } val localBlendFilter = blendFilter @@ -140,6 +166,8 @@ open class Layer internal constructor() { localBlendFilter.first.apply(localBlendFilter.second) localBlendFilter.first.apply(arrayOf(activeRenderTarget.colorBuffer(0), layerPost), activeRenderTarget.colorBuffer(0)) } + + accumulation?.copyTo(target.colorBuffer(0)) } } @@ -177,6 +205,13 @@ fun Layer.draw(function: () -> Unit) { drawFunc = function } +/** + * use the layer as a base + */ +fun Layer.use(vararg layer: Layer) { + copyLayers = layer.toList() +} + /** * the drawing acts as a mask on the layer */ diff --git a/orx-fx/README.md b/orx-fx/README.md index 3063b3dd..b5621048 100644 --- a/orx-fx/README.md +++ b/orx-fx/README.md @@ -32,8 +32,10 @@ Blend filters take two inputs ("source" and "destination"), they are intended to #### Porter-Duff blends - `SourceIn`, Porter-Duff source-in blend, intersect source and destination opacity and keep source colors - `SourceOut`, Porter-Duff source-out blend, subtract destination from source opacity and keep source colors + - `SourceAtop`, Porter-Duff source-atop blend, uses destination opacity, layers source on top and keeps both colors - `DestinationIn`, Porter-Duff destination-in blend, intersect source and destination opacity and keep source colors - `DestinationOut`, Porter-Duff destination-out blend, subtract destination from source opacity and keep destination colors + - `DestinationAtop`, Porter-Duff destination-atop blend, uses source opacity, layers destination on top and keeps both colors - `Xor`, Porter-Duff xor blend, picks colors from input with highest opacity or none with opacities are equal #### Various blends diff --git a/orx-fx/src/main/kotlin/blend/BlendFilters.kt b/orx-fx/src/main/kotlin/blend/BlendFilters.kt index d4071f55..1293919c 100644 --- a/orx-fx/src/main/kotlin/blend/BlendFilters.kt +++ b/orx-fx/src/main/kotlin/blend/BlendFilters.kt @@ -89,8 +89,10 @@ class Screen : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragm class SourceIn : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/source-in.frag"))) class SourceOut : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/source-out.frag"))) +class SourceAtop : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/source-atop.frag"))) class DestinationIn : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/destination-in.frag"))) class DestinationOut : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/destination-out.frag"))) +class DestinationAtop : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/destination-atop.frag"))) class Xor : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/xor.frag"))) class MultiplyContrast : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("blend/multiply-contrast.frag"))) diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-atop.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-atop.frag new file mode 100644 index 00000000..9248ac93 --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-atop.frag @@ -0,0 +1,17 @@ +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; +uniform sampler2D tex1; + +out vec4 o_color; + +void main() { + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); + + float lsrc = src.a * (1.0 - dest.a); + float lboth = src.a * dest.a; + + o_color = src * lsrc + dest * 0.0 + dest * lboth; +} \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-in.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-in.frag index 17783e68..b0b58b61 100644 --- a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-in.frag +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-in.frag @@ -7,9 +7,10 @@ uniform sampler2D tex1; out vec4 o_color; void main() { - vec4 a = texture(tex0, v_texCoord0); - vec4 b = texture(tex1, v_texCoord0); + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); - vec3 na = a.a == 0.0 ? vec3(0.0): a.rgb / a.a; - o_color = vec4(na, 1.0) * b.a * a.a; + float lboth = src.a * dest.a; + + o_color = dest * lboth; } \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-out.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-out.frag index 7060fac8..8cc1de0b 100644 --- a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-out.frag +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/destination-out.frag @@ -6,9 +6,10 @@ uniform sampler2D tex1; out vec4 o_color; void main() { - vec4 a = texture(tex0, v_texCoord0); - vec4 b = texture(tex1, v_texCoord0); + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); - vec3 na = a.a == 0.0 ? vec3(0.0): a.rgb / a.a; - o_color = vec4(na, 1.0) * max(a.a - b.a, 0.0); + float ldest = dest.a * (1.0 - src.a); + + o_color = dest * ldest; } \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-atop.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-atop.frag new file mode 100644 index 00000000..dae24d7d --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-atop.frag @@ -0,0 +1,17 @@ +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; +uniform sampler2D tex1; + +out vec4 o_color; + +void main() { + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); + + float ldest = dest.a * (1.0 - src.a); + float lboth = src.a * dest.a; + + o_color = dest * ldest + src * lboth; +} \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-in.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-in.frag index 112b13bb..297568b8 100644 --- a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-in.frag +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-in.frag @@ -6,9 +6,10 @@ uniform sampler2D tex1; out vec4 o_color; void main() { - vec4 a = texture(tex0, v_texCoord0); - vec4 b = texture(tex1, v_texCoord0); + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); - vec3 nb = b.a == 0.0 ? vec3(0.0): b.rgb / b.a; - o_color = vec4(nb, 1.0) * a.a * b.a; + float lboth = src.a * dest.a; + + o_color = src * lboth; } \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-out.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-out.frag index 86c9e2f1..dcb793fc 100644 --- a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-out.frag +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/source-out.frag @@ -6,9 +6,10 @@ uniform sampler2D tex1; out vec4 o_color; void main() { - vec4 a = texture(tex0, v_texCoord0); - vec4 b = texture(tex1, v_texCoord0); + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); - vec3 nb = b.a == 0.0 ? vec3(0.0): b.rgb / b.a; - o_color = vec4(nb, 1.0) * max(b.a - a.a, 0.0); + float lsrc = src.a * (1.0 - dest.a); + + o_color = src * lsrc; } \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/xor.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/xor.frag index c0ead762..2fd1e3eb 100644 --- a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/xor.frag +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blend/xor.frag @@ -6,19 +6,11 @@ uniform sampler2D tex1; out vec4 o_color; void main() { - vec4 a = texture(tex0, v_texCoord0); - vec4 b = texture(tex1, v_texCoord0); - vec4 color = vec4(0.0); + vec4 src = texture(tex0, v_texCoord0); + vec4 dest = texture(tex1, v_texCoord0); - vec3 na = a.a == 0.0 ? vec3(0.0) : a.rgb/a.a; - vec3 nb = b.a == 0.0 ? vec3(0.0) : b.rgb/b.a; - if (a.a > b.a) { - color = vec4(na, 1.0) * (b.a == 0.0? a.a : (1.0-b.a)); - } + float lsrc = src.a * (1.0 - dest.a); + float ldest = dest.a * (1.0 - src.a); - if (b.a > a.a) { - color = vec4(nb, 1.0) * (a.a == 0.0? b.a : (1.0-a.a)); - } - - o_color = color; + o_color = src * lsrc + dest * ldest; } \ No newline at end of file