Thickline
A class to draw variable width lines
imports
import org.openrndr.KEY_ESCAPE
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.math.Vector2
import org.openrndr.shape.ShapeContour
import org.openrndr.extra.videoprofiles.gif
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
fun main() = application {
configure {
width = 400
height = 400
}
program {
val thickLine = ThickLine(
200, ColorRGBa.WHITE, ColorRGBa.GRAY
) { t -> 10.0 - 10.0 * cos(t * PI * 2) }
// extend(ScreenRecorder()) { gif() }
extend {
drawer.clear(ColorRGBa.WHITE)
val thinLine = ShapeContour.fromPoints(List(50) {
val a = seconds * 2 + it * 0.08
Vector2(
sin(a + sin(a * 0.31)),
sin(a * 0.53 + sin(a * 0.73))
) * 160.0 + drawer.bounds.center
}, false)
thickLine.draw(drawer, thinLine)
}
keyboard.keyDown.listen {
if(it.key == KEY_ESCAPE) {
application.exit()
}
}
}
}
/**
* A class to draw [ShapeContour] objects as a thick line. The color is
* linearly interpolated from [color0] to [color1] from line start to end.
* The thickness of the line is defined by a function that takes a normalized
* `t` Double value as input and outputs the desired width. Get a uniform width
* using something like `{ t -> 10.0 }`
*/
class ThickLine(
private val pointCount: Int,
private val color0: ColorRGBa,
private val color1: ColorRGBa,
val width: (Double) -> Double
) {
val geometry = vertexBuffer(vertexFormat {
position(3)
color(4)
}, pointCount * 2)
fun draw(drawer: Drawer, thinLine: ShapeContour) {
drawer.shadeStyle = shadeStyle {
fragmentTransform = "x_fill = va_color;"
}
geometry.put {
for (i in 0 until pointCount) {
val pc = i / (pointCount - 1.0)
val color = color0.mix(color1, pc).toVector4()
val pos = thinLine.position(pc)
val normal = thinLine.normal(pc).normalized * width(pc) / 2.0
write((pos + normal).vector3(z = 0.0))
write(color)
write((pos - normal).vector3(z = 0.0))
write(color)
}
}
drawer.vertexBuffer(geometry, DrawPrimitive.TRIANGLE_STRIP)
}
}