# Drawing per-vertex colored meshes and variable thickness lines

**URL:** <https://openrndr.discourse.group/t/drawing-per-vertex-colored-meshes-and-variable-thickness-lines/266>\
**Category:** OPENRNDR\
**Created:** [July 25, 2021, 8:45pm UTC](https://openrndr.discourse.group/t/drawing-per-vertex-colored-meshes-and-variable-thickness-lines/266 "2021-07-25T20:45:16Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![abe](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/abe/32/700_2.png) [@abe](https://openrndr.discourse.group/u/abe)\
**Post date:** [January 29, 2022, 8:15pm UTC](https://openrndr.discourse.group/t/drawing-per-vertex-colored-meshes-and-variable-thickness-lines/266/3 "2022-01-29T20:15:27Z")

</div>

# _Thickline_

**A class to draw variable width lines**

![apps4.WigglyLine2-2022-01-29-21.06.05](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/c20686b9d8d69443518c6954352c3d66e0446189.gif)

> **imports**
>
> ```auto
> 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
> 
> ```

```auto
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)
    }
}

```

---

_[View the full topic](https://openrndr.discourse.group/t/drawing-per-vertex-colored-meshes-and-variable-thickness-lines/266)._
