v2 / vlib / gg / bezier.c.v
57 lines · 53 sloc · 2.21 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1module gg
2
3import math
4import sokol.sgl
5
6// draw_cubic_bezier_recursive draws a cubic Bézier curve, also known as a spline, from four points,
7// where the first and the last points, *will* be part of the curve, and the middle 2 points are control ones.
8// Unlike `draw_cubic_bezier_in_steps`, this method does not use a fixed number of steps for the whole curve,
9// but tries to produce more tesselation points dynamically for the curvier parts.
10@[direct_array_access]
11pub fn (ctx &Context) draw_cubic_bezier_recursive(points []f32, c Color) {
12 if points.len < 8 {
13 return
14 }
15 ctx.draw_cubic_bezier_recursive_scalar(points[0], points[1], points[2], points[3], points[4],
16 points[5], points[6], points[7], c)
17}
18
19// draw_cubic_bezier_recursive_scalar is the same as `draw_cubic_bezier_recursive`, except that the `points` are given
20// as indiviual x,y f32 scalar parameters, and not in a single dynamic array parameter.
21pub fn (ctx &Context) draw_cubic_bezier_recursive_scalar(x1 f32, y1 f32, x2 f32, y2 f32, x3 f32, y3 f32,
22 x4 f32, y4 f32, c Color) {
23 if c.a == 0 {
24 return
25 }
26 if c.a != 255 {
27 sgl.load_pipeline(ctx.pipeline.alpha)
28 }
29 sgl.c4b(c.r, c.g, c.b, c.a)
30 sgl.begin_line_strip()
31 sgl.v2f(x1 * ctx.scale, y1 * ctx.scale)
32 ctx.cubic_bezier_rec(x1, y1, x2, y2, x3, y3, x4, y4, 0)
33 sgl.v2f(x4 * ctx.scale, y4 * ctx.scale)
34 sgl.end()
35}
36
37// based on nsvg__flattenCubicBez, from https://github.com/memononen/nanosvg/ :
38fn (ctx &Context) cubic_bezier_rec(x1 f32, y1 f32, x2 f32, y2 f32, x3 f32, y3 f32, x4 f32, y4 f32, level int) {
39 if level > 10 {
40 return
41 }
42 dx, dy := x4 - x1, y4 - y1
43 d2 := math.abs((x2 - x4) * dy - (y2 - y4) * dx)
44 d3 := math.abs((x3 - x4) * dy - (y3 - y4) * dx)
45 if (d2 + d3) * (d2 + d3) < 0.25 * (dx * dx + dy * dy) {
46 sgl.v2f(x4 * ctx.scale, y4 * ctx.scale)
47 return
48 }
49 x12, y12 := 0.5 * (x1 + x2), 0.5 * (y1 + y2)
50 x23, y23 := 0.5 * (x2 + x3), 0.5 * (y2 + y3)
51 x34, y34 := 0.5 * (x3 + x4), 0.5 * (y3 + y4)
52 x234, y234 := 0.5 * (x23 + x34), 0.5 * (y23 + y34)
53 x123, y123 := 0.5 * (x12 + x23), 0.5 * (y12 + y23)
54 x1234, y1234 := 0.5 * (x123 + x234), 0.5 * (y123 + y234)
55 ctx.cubic_bezier_rec(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1)
56 ctx.cubic_bezier_rec(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1)
57}
58