- Adjust some demo window sizes. - Replace Random.double by Double.uniform - Tweak some demos so screenshots look more interesting
254 lines
6.3 KiB
Markdown
254 lines
6.3 KiB
Markdown
# orx-compositor
|
|
|
|
Toolkit to make composite (layered) images using blend modes and filters.
|
|
|
|
## Usage
|
|
|
|
A `Composite` is made using the `compose {}` builder. We start with a very simple example:
|
|
```kotlin
|
|
fun main() = application {
|
|
program {
|
|
val composite = compose {
|
|
// this is only executed once
|
|
val position = Vector2(100.0, 100.0)
|
|
|
|
draw {
|
|
// code inside draw blocks is executed whenever the composite is drawn
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
}
|
|
extend {
|
|
// draw the composite
|
|
composite.draw(drawer)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Layers
|
|
|
|
A `Composite` with two layers looks like this.
|
|
|
|
```kotlin
|
|
fun main() = application {
|
|
program {
|
|
val composite = compose {
|
|
// this layer is drawn first
|
|
layer {
|
|
val position = Vector2(100.0, 100.0)
|
|
draw {
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
}
|
|
|
|
// this layer is drawn second
|
|
layer {
|
|
val position = Vector2(150.0, 150.0)
|
|
draw {
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
blend(Multiply())
|
|
}
|
|
}
|
|
extend {
|
|
// draw the composite
|
|
composite.draw(drawer)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Layers can be nested:
|
|
|
|
```kotlin
|
|
fun main() = application {
|
|
program {
|
|
val composite = compose {
|
|
layer {
|
|
layer {
|
|
// this draw is processed first
|
|
draw { }
|
|
}
|
|
layer {
|
|
// this draw is processed second
|
|
draw { }
|
|
}
|
|
val position = Vector2(100.0, 100.0)
|
|
draw {
|
|
// this draw is processed third
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
}
|
|
|
|
// this layer is drawn second
|
|
layer {
|
|
val position = Vector2(150.0, 150.0)
|
|
draw {
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
blend(Multiply())
|
|
}
|
|
}
|
|
extend {
|
|
// draw the composite
|
|
composite.draw(drawer)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Asides
|
|
|
|
An aside is a layer which output is not directly included in the composite drawing. The contents of an aside can be used in layers and post-processing.
|
|
|
|
```kotlin
|
|
fun main() = application {
|
|
program {
|
|
val composite = compose {
|
|
|
|
val a = aside {
|
|
val position = Vector2(250.0, 250.0)
|
|
draw {
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
}
|
|
|
|
// this layer is drawn second
|
|
layer {
|
|
val position = Vector2(150.0, 150.0)
|
|
draw {
|
|
drawer.image(a)
|
|
drawer.circle(position, 100.0)
|
|
}
|
|
blend(Multiply())
|
|
}
|
|
}
|
|
extend {
|
|
// draw the composite
|
|
composite.draw(drawer)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
### Post-processing
|
|
|
|
```kotlin
|
|
fun main() = application {
|
|
program {
|
|
val composite = compose {
|
|
layer {
|
|
draw {
|
|
|
|
}
|
|
// the first Filter1to1 to apply
|
|
post(ApproximateGaussianBlur()) {
|
|
// here is code that is executed everytime the layer is drawn
|
|
}
|
|
|
|
// the second Filter1to1 to apply
|
|
post(ColorCorrection()) {
|
|
// here is code that is executed everytime the layer is drawn
|
|
}
|
|
}
|
|
}
|
|
extend {
|
|
// draw the composite
|
|
composite.draw(drawer)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
#### Using filters with multiple inputs
|
|
|
|
Some filters use more than a single input in producing their output, these filters inherit from Filter2to1, Filter3to1, Filter4to1 etc.
|
|
One such filter is `DirectionalBlur` which has image and direction field inputs. In the following example we use an aside to
|
|
draw a direction field which is fed into the blur filter.
|
|
|
|
```kotlin
|
|
fun main() = application {
|
|
program {
|
|
val composite = compose {
|
|
val directionField = aside {
|
|
draw {
|
|
// [...]
|
|
}
|
|
}
|
|
layer {
|
|
draw {
|
|
// [...]
|
|
}
|
|
post(DirectionalBlur(), directionField)
|
|
}
|
|
}
|
|
extend {
|
|
// draw the composite
|
|
composite.draw(drawer)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Example
|
|
|
|
```kotlin
|
|
import org.openrndr.application
|
|
import org.openrndr.draw.loadImage
|
|
import org.openrndr.extra.compositor.*
|
|
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
|
|
|
|
fun main() = application {
|
|
configure {
|
|
width = 768
|
|
height = 768
|
|
}
|
|
program {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<!-- __demos__ -->
|
|
## Demos
|
|
### DemoAside01
|
|
[source code](src/jvmDemo/kotlin/DemoAside01.kt)
|
|
|
|

|
|
|
|
### DemoCompositor01
|
|
[source code](src/jvmDemo/kotlin/DemoCompositor01.kt)
|
|
|
|

|
|
|
|
### DemoCompositor02
|
|
[source code](src/jvmDemo/kotlin/DemoCompositor02.kt)
|
|
|
|

|