From 4fa6ea925a88a6aba0d987ec2c7573866e15af53 Mon Sep 17 00:00:00 2001 From: David Thomas Date: Tue, 13 Feb 2024 22:59:50 +0000 Subject: [PATCH] Move forward diff routine out, scaling calcs, basic tests, simple clipping --- include/framebuf/curve.h | 8 ++ libraries/framebuf/curve/curve.c | 120 ++++++++++++++++++++- libraries/framebuf/curve/test/curve-test.c | 106 ++++++++---------- libraries/framebuf/screen/screen.c | 46 +++++--- 4 files changed, 198 insertions(+), 82 deletions(-) diff --git a/include/framebuf/curve.h b/include/framebuf/curve.h index 7aafcf4..004cafb 100644 --- a/include/framebuf/curve.h +++ b/include/framebuf/curve.h @@ -62,4 +62,12 @@ point_t curve_bezier_point_on_quintic_r(point_t p0, point_t p5, fix16_t t); +// uses forward differencing (float version) +void curve_bezier_cubic_f(point_t p0, + point_t p1, + point_t p2, + point_t p3, + int nsteps, + point_t *points); + #endif /* DPTLIB_CURVE_H */ diff --git a/libraries/framebuf/curve/curve.c b/libraries/framebuf/curve/curve.c index 48c315b..97742d1 100644 --- a/libraries/framebuf/curve/curve.c +++ b/libraries/framebuf/curve/curve.c @@ -20,6 +20,26 @@ point_t curve_point_on_line(point_t p0, point_t p1, fix16_t t) return c; } +#define SCALE (16) + +static point_t scale_up(point_t p) +{ + point_t q; + + q.x = p.x * SCALE; + q.y = p.y * SCALE; + return q; +} + +static point_t scale_down(point_t p) +{ + point_t q; + + q.x = p.x / SCALE; + q.y = p.y / SCALE; + return q; +} + point_t curve_bezier_point_on_quad(point_t p0, point_t p1, point_t p2, @@ -28,12 +48,16 @@ point_t curve_bezier_point_on_quad(point_t p0, point_t a, b; point_t ab; + p0 = scale_up(p0); + p1 = scale_up(p1); + p2 = scale_up(p2); + a = curve_point_on_line(p0, p1, t); b = curve_point_on_line(p1, p2, t); ab = curve_point_on_line(a, b, t); - return ab; + return scale_down(ab); } point_t curve_bezier_point_on_cubic(point_t p0, @@ -46,6 +70,11 @@ point_t curve_bezier_point_on_cubic(point_t p0, point_t ab, bc; point_t abc; + p0 = scale_up(p0); + p1 = scale_up(p1); + p2 = scale_up(p2); + p3 = scale_up(p3); + a = curve_point_on_line(p0, p1, t); b = curve_point_on_line(p1, p2, t); c = curve_point_on_line(p2, p3, t); @@ -55,7 +84,7 @@ point_t curve_bezier_point_on_cubic(point_t p0, abc = curve_point_on_line(ab, bc, t); - return abc; + return scale_down(abc); } point_t curve_bezier_point_on_quartic(point_t p0, @@ -70,6 +99,12 @@ point_t curve_bezier_point_on_quartic(point_t p0, point_t abc, bcd; point_t abcd; + p0 = scale_up(p0); + p1 = scale_up(p1); + p2 = scale_up(p2); + p3 = scale_up(p3); + p4 = scale_up(p4); + a = curve_point_on_line(p0, p1, t); b = curve_point_on_line(p1, p2, t); c = curve_point_on_line(p2, p3, t); @@ -84,7 +119,7 @@ point_t curve_bezier_point_on_quartic(point_t p0, abcd = curve_point_on_line(abc, bcd, t); - return abcd; + return scale_down(abcd); } point_t curve_bezier_point_on_quintic(point_t p0, @@ -101,6 +136,13 @@ point_t curve_bezier_point_on_quintic(point_t p0, point_t abcd, bcde; point_t abcde; + p0 = scale_up(p0); + p1 = scale_up(p1); + p2 = scale_up(p2); + p3 = scale_up(p3); + p4 = scale_up(p4); + p5 = scale_up(p5); + a = curve_point_on_line(p0, p1, t); b = curve_point_on_line(p1, p2, t); c = curve_point_on_line(p2, p3, t); @@ -121,7 +163,7 @@ point_t curve_bezier_point_on_quintic(point_t p0, abcde = curve_point_on_line(abcd, bcde, t); - return abcde; + return scale_down(abcde); } /* ----------------------------------------------------------------------- */ @@ -179,3 +221,73 @@ point_t curve_bezier_point_on_quintic_r(point_t p0, return abcde; } + +/* ----------------------------------------------------------------------- */ + +void curve_bezier_cubic_f(point_t p0, + point_t p1, + point_t p2, + point_t p3, + int nsteps, + point_t *points) +{ + float cx, cy; + float bx, by; + float ax, ay; + float h, hh, hhh; + float d1x, d1y; + float d2x, d2y; + float d3x, d3y; + float curx, cury; + int i; + point_t *point; + + cx = 3.0f * (p1.x - p0.x); + cy = 3.0f * (p1.y - p0.y); + + bx = 3.0f * (p2.x - p1.x) - cx; + by = 3.0f * (p2.y - p1.y) - cy; + + ax = p3.x - p0.x - cx - bx; + ay = p3.y - p0.y - cy - by; + + h = 1.0f / nsteps; + hh = h * h; + hhh = hh * h; + + /* first difference */ + d1x = ax * hhh + bx * hh + cx * h; + d1y = ay * hhh + by * hh + cy * h; + + /* second difference */ + d2x = 6.0f * ax * hhh + 2.0f * bx * hh; + d2y = 6.0f * ay * hhh + 2.0f * by * hh; + + /* third difference */ + d3x = 6.0f * ax * hhh; + d3y = 6.0f * ay * hhh; + + point = &points[0]; + + curx = p0.x; + cury = p0.y; + + for (i = 0; ; i++) + { + point->x = curx; + point->y = cury; + point++; + + if (i == nsteps) + break; + + curx += d1x; + cury += d1y; + + d1x += d2x; + d1y += d2y; + + d2x += d3x; + d2y += d3y; + } +} diff --git a/libraries/framebuf/curve/test/curve-test.c b/libraries/framebuf/curve/test/curve-test.c index 10d0800..3a6e44b 100644 --- a/libraries/framebuf/curve/test/curve-test.c +++ b/libraries/framebuf/curve/test/curve-test.c @@ -245,6 +245,36 @@ curveteststate_t; /* ----------------------------------------------------------------------- */ +static result_t curve_basic_test(curveteststate_t *state) +{ + point_t a = { 0, 0 }; + point_t b = { 100, 100 }; + + point_t c = curve_point_on_line(a, b, 0); + assert(c.x == a.x); + assert(c.y == a.y); + + point_t d = curve_point_on_line(a, b, 65536); + assert(d.x == b.x); + assert(d.y == b.y); + + point_t e = curve_point_on_line(a, b, 65536 / 2); + assert(e.x == 50); + assert(e.y == 50); + + point_t f = curve_point_on_line(a, b, 65536 * 1 / 3); + assert(f.x == 33); + assert(f.y == 33); + + point_t g = curve_point_on_line(a, b, 65536 * 2 / 3); + assert(g.x == 66); + assert(g.y == 66); + + return result_TEST_PASSED; +} + +/* ----------------------------------------------------------------------- */ + static point_t jitter_on(point_t p) { point_t q; @@ -262,62 +292,6 @@ static point_t jitter_off(point_t p) /* ----------------------------------------------------------------------- */ -void calcBezier(point_t p1, point_t p2, point_t p3, point_t p4, - int nsteps, point_t *points) -{ - float cx = 3 * (p2.x - p1.x); - float cy = 3 * (p2.y - p1.y); - - float bx = 3 * (p3.x - p2.x) - cx; - float by = 3 * (p3.y - p2.y) - cy; - - float ax = p4.x - p1.x - cx - bx; - float ay = p4.y - p1.y - cy - by; - - float h = 1.0f / nsteps; - float hh = h * h; - float hhh = hh * h; - - // first difference - float d1x = ax * hhh + bx * hh + cx * h; - float d1y = ay * hhh + by * hh + cy * h; - - // second - float d2x = 6 * ax * hhh + 2 * bx * hh; - float d2y = 6 * ay * hhh + 2 * by * hh; - - // third - float d3x = 6 * ax * hhh; - float d3y = 6 * ay * hhh; - - float currentX = p1.x; - float currentY = p1.y; - - points[0].x = currentX; - points[0].y = currentY; - - // skip first and last points - for (int i = 1; i < nsteps; i++) - { - currentX += d1x; - currentY += d1y; - - d1x += d2x; - d1y += d2y; - - d2x += d3x; - d2y += d3y; - - points[i].x = currentX; - points[i].y = currentY; - } - - points[nsteps].x = p4.x; - points[nsteps].y = p4.y; -} - -/* ----------------------------------------------------------------------- */ - static void setup_all_curves(curveteststate_t *state) { int cpi; @@ -418,25 +392,30 @@ static void calc_all_curves(curveteststate_t *state) { int set; int o; + int np; int i; int t; for (set = 0; set < NELEMS(curves); set++) { o = curves[set].offset; + np = curves[set].npoints; if (curves[set].kind == FwdDiffCubic) { - calcBezier(state->jitterfn(state->control_points[o + 0]), - state->jitterfn(state->control_points[o + 1]), - state->jitterfn(state->control_points[o + 2]), - state->jitterfn(state->control_points[o + 3]), - state->nsegments, - &state->draw_points[0]); + curve_bezier_cubic_f(state->jitterfn(state->control_points[o + 0]), + state->jitterfn(state->control_points[o + 1]), + state->jitterfn(state->control_points[o + 2]), + state->jitterfn(state->control_points[o + 3]), + state->nsegments, + &state->draw_points[0]); } else { - for (i = 0; i < state->nsegments + 1; i++) + state->draw_points[0] = state->jitterfn(state->control_points[o]); + state->draw_points[state->nsegments] = state->jitterfn(state->control_points[o + np - 1]); + + for (i = 1; i < state->nsegments; i++) { t = 65536 * i / state->nsegments; @@ -795,6 +774,7 @@ result_t curve_test_one_format(const char *resources, static const curvetestfn_t tests[] = { + curve_basic_test, curve_interactive_test }; diff --git a/libraries/framebuf/screen/screen.c b/libraries/framebuf/screen/screen.c index 9b738f9..107e307 100644 --- a/libraries/framebuf/screen/screen.c +++ b/libraries/framebuf/screen/screen.c @@ -168,23 +168,21 @@ void screen_draw_line(screen_t *scr, int x0, int y0, int x1, int y1, colour_t colour) { - // box_t screen_box; - // box_t line_box; - // box_t draw_box; + box_t screen_box; + box_t line_box; + box_t draw_box; // int clipped_width, clipped_height; // pixelfmt_any_t fmt; - // - // if (screen_get_clip(scr, &screen_box)) - // return; /* invalid clipped screen */ - // - // line_box.x0 = x0; - // line_box.y0 = y0; - // line_box.x1 = x1; - // line_box.y1 = y1; - // if (box_intersection(&screen_box, &line_box, &draw_box)) - // return; - // - // clipped_width = draw_box.x1 - draw_box.x0; + + if (screen_get_clip(scr, &screen_box)) + return; /* invalid clipped screen */ + + box_reset(&line_box); + box_extend_n(&line_box, 2, x0, y0, x1, y1); + if (box_intersection(&screen_box, &line_box, &draw_box)) + return; /* intersection was empty */ + + // clipped_width = draw_box.x1 - draw_box.x0; // clipped_height = draw_box.y1 - draw_box.y0; int dx, dy; @@ -229,6 +227,24 @@ void screen_draw_aa_linef(screen_t *scr, float x0, float y0, float x1, float y1, colour_t colour) { + box_t screen_box; + box_t line_box; + box_t draw_box; + // int clipped_width, clipped_height; + // pixelfmt_any_t fmt; + + if (screen_get_clip(scr, &screen_box)) + return; /* invalid clipped screen */ + + box_reset(&line_box); + box_extend_n(&line_box, 2, (int) x0, (int) y0, (int) x1, (int) y1); + if (box_intersection(&screen_box, &line_box, &draw_box)) + return; /* intersection was empty */ + + // clipped_width = draw_box.x1 - draw_box.x0; + // clipped_height = draw_box.y1 - draw_box.y0; + + float dx, dy; float steep; float grad;