| 1 | module gg |
| 2 | |
| 3 | import math |
| 4 | import 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] |
| 11 | pub 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. |
| 21 | pub 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/ : |
| 38 | fn (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 | |