I find interesting that adding elements to a canvas is easier than removing them, be it on a piece of paper, with oil paint on a canvas, or with a colorBuffer
.
Now that I think about it, we do have a drawer
in OPENRNDR, which is used to draw things. But where is our eraser
?
Today I needed to erase some pixels so I thought I would share here the approach I used.
Imports
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.BlendMode
import org.openrndr.draw.colorBuffer
import org.openrndr.drawImage
import org.openrndr.extensions.Screenshots
import org.openrndr.extra.fx.patterns.Checkers
import org.openrndr.extra.shapes.primitives.regularPolygon
import org.openrndr.shape.Circle
fun main() = application {
program {
// A background checkers pattern
val checkers = colorBuffer(width, height)
Checkers().apply(checkers, checkers)
val img = drawImage(width, height) {
// Draw a circle
contour(Circle(bounds.center, 200.0).contour)
// Erase a pentagon
drawStyle.blendMode = BlendMode.REPLACE
fill = ColorRGBa.TRANSPARENT
contour(regularPolygon(5, bounds.center, 100.0, 5.0).contour)
}
extend {
drawer.image(checkers)
drawer.image(img)
}
}
}
The program starts by creating a checkers pattern to use as a background. It will help notice the transparency.
Next we use drawImage
to create an image with transparent background (its default), then we draw a circle into it, and erase a pentagon. The erasing trick is to use the REPLACE
blend mode, together with a transparent fill color.
I can’t remember if drawImage
is available with the main
branch of openrndr-template
. If not, you can switch to the next-version
branch. This method makes it easy to draw an image (instead of loading it from the disk).
Note 1
One shouldn’t use drawImage
inside extend
: it’s a one-time thing. If you need to update the drawing on every frame use a renderTarget
instead.
Note 2
contour(Circle(bounds.center, 200.0).contour)
can be written shorter, as
circle(bounds.center, 200.0)
I chose the longer one so both shapes are drawn the same way, with drawer.contour
.
Note 3
This example assumes we actually want a colorBuffer
(a bitmap). We could instead create a Shape
with an outer ShapeContour
(the circle) and an inner one (the pentagon). That way it would be all vector data, which is better for drawing at different sizes, for pen plotters, or for querying contour locations and vertices, or for adjusting those contours programmatically.