// openrndr 0.4
fun main() = application {
configure {
width = 800
height = 800
}
program {
// create a buffer and specify it's format and size.
val geometry = vertexBuffer(vertexFormat {
position(3)
color(4)
}, 3 * 100)
// create an area with some padding around the edges
val area = drawer.bounds.offsetEdges(-50.0)
// populate the vertex buffer.
geometry.put {
for (i in 0 until geometry.vertexCount) {
write(area.randomPoint().vector3(z = 0.0))
write(Random.vector4(0.0, 1.0))
}
}
extend {
// shader using the color attributes from our buffer
drawer.shadeStyle = shadeStyle {
fragmentTransform = "x_fill = va_color;"
}
drawer.vertexBuffer(geometry, DrawPrimitive.TRIANGLES)
}
}
}
/**
* Returns a random point inside a rectangle
*/
fun Rectangle.randomPoint(): Vector2 {
return Vector2.uniform(this.corner, this.corner + this.dimensions)
}
The code above was a preparation for this program, which converts an open animated shapeContour into a mesh (a triangle strip) with variable width and unique colors per vertex.
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)
}
}