Clean up line rendering code. Slightly hacky but works in the 99% case
This commit is contained in:
parent
4df5f443a0
commit
6b2c3cd5bb
1 changed files with 73 additions and 19 deletions
|
@ -44,6 +44,8 @@ import kotlin.math.sin
|
||||||
*/
|
*/
|
||||||
val NOISE: PerlinNoise = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4))
|
val NOISE: PerlinNoise = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4))
|
||||||
|
|
||||||
|
val CAP_THETA: Float = 18f
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a sequence of linePoints spanning the given points.
|
* Draw a sequence of linePoints spanning the given points.
|
||||||
*
|
*
|
||||||
|
@ -77,38 +79,84 @@ fun drawLineSeq(
|
||||||
val tess = Tesselator.getInstance()
|
val tess = Tesselator.getInstance()
|
||||||
val buf = tess.builder
|
val buf = tess.builder
|
||||||
|
|
||||||
// We use one single TRIANGLE_STRIP
|
|
||||||
// in order to connect adjacent segments together and not get the weird hinge effect.
|
|
||||||
// There's still some artifacting but this is passable, at least.
|
|
||||||
buf.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR)
|
|
||||||
|
|
||||||
val n = points.size
|
val n = points.size
|
||||||
|
val joinAngles = FloatArray(n)
|
||||||
|
val joinOffsets = FloatArray(n)
|
||||||
|
for (i in 2..n-1) {
|
||||||
|
val p0 = points[i - 2];
|
||||||
|
val p1 = points[i - 1];
|
||||||
|
val p2 = points[i];
|
||||||
|
val prev = p1.add(p0.negated())
|
||||||
|
val next = p2.add(p1.negated())
|
||||||
|
val angle = Mth.atan2((prev.x * next.y - prev.y * next.x).toDouble(), (prev.x * next.x + prev.y * next.y).toDouble()).toFloat()
|
||||||
|
joinAngles[i - 1] = angle
|
||||||
|
val clamp = Math.min(prev.length(), next.length()) / (width * 0.5f);
|
||||||
|
joinOffsets[i - 1] = Mth.clamp(Mth.sin(angle) / (1 + Mth.cos(angle)), -clamp, clamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun vertex(color: BlockPos, pos: Vec2) = buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex()
|
||||||
for ((i, pair) in points.zipWithNext().withIndex()) {
|
for ((i, pair) in points.zipWithNext().withIndex()) {
|
||||||
val (p1, p2) = pair
|
val (p1, p2) = pair
|
||||||
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163
|
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163
|
||||||
// GuiComponent::innerFill line 52
|
// GuiComponent::innerFill line 52
|
||||||
// fedor have useful variable names challenge (99% can't beat)
|
// fedor have useful variable names challenge (99% can't beat)
|
||||||
val dx = p2.x - p1.x
|
val tangent = p2.add(p1.negated()).normalized().scale(width * 0.5f)
|
||||||
val dy = p2.y - p1.y
|
val normal = Vec2(-tangent.y, tangent.x)
|
||||||
// normal x and y, presumably?
|
|
||||||
val nx = -dy
|
|
||||||
val ny = dx
|
|
||||||
// thickness?
|
|
||||||
val tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f)
|
|
||||||
val tx = nx / tlen
|
|
||||||
val ty = ny / tlen
|
|
||||||
|
|
||||||
fun color(time: Float): BlockPos =
|
fun color(time: Float): BlockPos =
|
||||||
BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt())
|
BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt())
|
||||||
|
|
||||||
val color1 = color(i.toFloat() / n)
|
val color1 = color(i.toFloat() / n)
|
||||||
val color2 = color((i + 1f) / n)
|
val color2 = color((i + 1f) / n)
|
||||||
buf.vertex(mat, p1.x + tx, p1.y + ty, z).color(color1.x, color1.y, color1.z, a).endVertex()
|
val jlow = joinOffsets[i]
|
||||||
buf.vertex(mat, p1.x - tx, p1.y - ty, z).color(color1.x, color1.y, color1.z, a).endVertex()
|
val jhigh = joinOffsets[i + 1]
|
||||||
buf.vertex(mat, p2.x + tx, p2.y + ty, z).color(color2.x, color2.y, color2.z, a).endVertex()
|
buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
|
||||||
buf.vertex(mat, p2.x - tx, p2.y - ty, z).color(color2.x, color2.y, color2.z, a).endVertex()
|
vertex(color1, p1.add(tangent.scale(Math.max(0f, jlow))).add(normal))
|
||||||
|
vertex(color1, p1)
|
||||||
|
vertex(color1, p1.add(tangent.scale(Math.max(0f, -jlow))).add(normal.negated()))
|
||||||
|
vertex(color2, p2.add(tangent.scale(Math.max(0f, -jhigh)).negated()).add(normal.negated()))
|
||||||
|
vertex(color2, p2)
|
||||||
|
vertex(color2, p2.add(tangent.scale(Math.max(0f, jhigh)).negated()).add(normal))
|
||||||
|
tess.end()
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
val sangle = joinAngles[i]
|
||||||
|
val angle = Math.abs(sangle)
|
||||||
|
val rnormal = normal.negated()
|
||||||
|
val joinSteps = Mth.ceil(angle * 180 / (CAP_THETA * Mth.PI))
|
||||||
|
if (joinSteps < 1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
|
||||||
|
buf.vertex(mat, p1.x, p1.y, z).color(color1.x, color1.y, color1.z, a).endVertex()
|
||||||
|
if (sangle < 0) {
|
||||||
|
for (j in 0..joinSteps) {
|
||||||
|
val fan = rotate(rnormal, -sangle * (j.toFloat() / joinSteps))
|
||||||
|
buf.vertex(mat, p1.x - fan.x, p1.y - fan.y, z).color(color1.x, color1.y, color1.z, a).endVertex()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (j in joinSteps downTo 0) {
|
||||||
|
val fan = rotate(normal, -sangle * (j.toFloat() / joinSteps))
|
||||||
|
buf.vertex(mat, p1.x - fan.x, p1.y - fan.y, z).color(color1.x, color1.y, color1.z, a).endVertex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tess.end()
|
tess.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun drawCaps(color: BlockPos, point: Vec2, prev: Vec2) {
|
||||||
|
val tangent = point.add(prev.negated()).normalized().scale(0.5f * width)
|
||||||
|
val normal = Vec2(-tangent.y, tangent.x)
|
||||||
|
val joinSteps = Mth.ceil(180f / CAP_THETA)
|
||||||
|
buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
|
||||||
|
vertex(color, point)
|
||||||
|
for (j in joinSteps downTo 0) {
|
||||||
|
val fan = rotate(normal, -Mth.PI * (j.toFloat() / joinSteps))
|
||||||
|
buf.vertex(mat, point.x + fan.x, point.y + fan.y, z).color(color.x, color.y, color.z, a).endVertex()
|
||||||
|
}
|
||||||
|
tess.end()
|
||||||
|
}
|
||||||
|
drawCaps(BlockPos(r1.toInt(), g1.toInt(), b1.toInt()), points[0], points[1])
|
||||||
|
drawCaps(BlockPos(r2.toInt(), g2.toInt(), b2.toInt()), points[n - 1], points[n - 2])
|
||||||
|
|
||||||
if (animTime != null) {
|
if (animTime != null) {
|
||||||
val pointCircuit =
|
val pointCircuit =
|
||||||
|
@ -137,6 +185,12 @@ fun drawLineSeq(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun rotate(vec: Vec2, theta: Float): Vec2 {
|
||||||
|
val cos = Mth.cos(theta)
|
||||||
|
val sin = Mth.sin(theta)
|
||||||
|
return Vec2(vec.x * cos - vec.y * sin, vec.y * cos + vec.x * sin)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it,
|
* * Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it,
|
||||||
* * you have to do the conversion yourself.)
|
* * you have to do the conversion yourself.)
|
||||||
|
|
Loading…
Reference in a new issue