From fd3c7753435658a6aeebf1b68d18178a6c7cf57d Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 6 Jan 2010 22:26:55 +0000 Subject: add bezier curve plotters svn path=/trunk/libnsfb/; revision=9794 --- include/libnsfb.h | 20 +++++++++ include/libnsfb_plot.h | 4 ++ include/nsfb_plot.h | 10 +++++ src/plot.c | 11 +++++ src/plotters.c | 88 ++++++++++++++++++++++++++++++++++++++ test/Makefile | 2 +- test/bezier.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 test/bezier.c diff --git a/include/libnsfb.h b/include/libnsfb.h index 5975768..41490ad 100644 --- a/include/libnsfb.h +++ b/include/libnsfb.h @@ -15,9 +15,29 @@ typedef struct nsfb_cursor_s nsfb_cursor_t; typedef struct nsfb_s nsfb_t; + +/** representation of a colour. + * + * The colour value comprises of four components arranged in the order ABGR: + * bits 24-31 are the alpha value and represent the opacity. 0 is + * transparent i.e. there would be no change in the target surface if + * this colour were to be used and 0xFF is opaque. + * + * bits 16-23 are the Blue component of the colour. + * + * bits 8-15 are the Green component of the colour. + * + * bits 0-7 are the Red component of the colour. + */ typedef uint32_t nsfb_colour_t; typedef struct nsfb_event_s nsfb_event_t; +/** co-ordinate for plotting operations */ +typedef struct nsfb_point_s { + int x; + int y; +} nsfb_point_t; + /** bounding box for plotting operations */ typedef struct nsfb_bbox_s { int x0; diff --git a/include/libnsfb_plot.h b/include/libnsfb_plot.h index 45aad28..1d420b0 100644 --- a/include/libnsfb_plot.h +++ b/include/libnsfb_plot.h @@ -78,6 +78,10 @@ bool nsfb_plot_arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, int angle */ bool nsfb_plot_point(nsfb_t *nsfb, int x, int y, nsfb_colour_t c); +bool nsfb_plot_cubic_bezier(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_point_t *ctrlb, nsfb_colour_t c); + +bool nsfb_plot_quadratic_bezier(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_colour_t cl); + /** copy an area of screen * * Copy an area of the display. diff --git a/include/nsfb_plot.h b/include/nsfb_plot.h index 790a923..52af7cd 100644 --- a/include/nsfb_plot.h +++ b/include/nsfb_plot.h @@ -83,6 +83,14 @@ typedef bool (nsfb_plotfn_glyph1_t)(nsfb_t *nsfb, nsfb_bbox_t *loc, const uint8_ */ typedef bool (nsfb_plotfn_readrect_t)(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer); +/** Plot quadratic bezier spline + */ +typedef bool (nsfb_plotfn_quadratic_bezier_t)(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_colour_t c); + +/** Plot cubic bezier spline + */ +typedef bool (nsfb_plotfn_cubic_bezier_t)(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_point_t *ctrlb, nsfb_colour_t c); + /** plotter function table. */ typedef struct nsfb_plotter_fns_s { nsfb_plotfn_clg_t *clg; @@ -101,6 +109,8 @@ typedef struct nsfb_plotter_fns_s { nsfb_plotfn_glyph8_t *glyph8; nsfb_plotfn_glyph1_t *glyph1; nsfb_plotfn_readrect_t *readrect; + nsfb_plotfn_quadratic_bezier_t *quadratic; + nsfb_plotfn_cubic_bezier_t *cubic; } nsfb_plotter_fns_t; diff --git a/src/plot.c b/src/plot.c index 55437cf..6303127 100644 --- a/src/plot.c +++ b/src/plot.c @@ -140,3 +140,14 @@ bool nsfb_plot_readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer) { return nsfb->plotter_fns->readrect(nsfb, rect, buffer); } + + +bool nsfb_plot_cubic_bezier(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_point_t *ctrlb, nsfb_colour_t c) +{ + return nsfb->plotter_fns->cubic(nsfb, curve, ctrla, ctrlb, c); +} + +bool nsfb_plot_quadratic_bezier(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_colour_t c) +{ + return nsfb->plotter_fns->quadratic(nsfb, curve, ctrla, c); +} diff --git a/src/plotters.c b/src/plotters.c index 82deb0f..60826d3 100644 --- a/src/plotters.c +++ b/src/plotters.c @@ -435,6 +435,8 @@ static bool ellipse_fill(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c) } } + + /* copy an area of screen from one location to another. * * @warning This implementation is woefully incomplete! @@ -504,6 +506,90 @@ static bool arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, int angle2, return true; } +#define N_SEG 30 + +static bool cubic(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_point_t *ctrlb, nsfb_colour_t cl) +{ + nsfb_bbox_t line; + + unsigned int seg_loop; + double t; + double one_minus_t; + double a; + double b; + double c; + double d; + double x; + double y; + + x = curve->x0; + y = curve->y0; + + for (seg_loop = 1; seg_loop <= N_SEG; ++seg_loop) { + t = (double)seg_loop / (double)N_SEG; + + one_minus_t = 1.0 - t; + + a = one_minus_t * one_minus_t * one_minus_t; + b = 3.0 * t * one_minus_t * one_minus_t; + c = 3.0 * t * t * one_minus_t; + d = t * t * t; + + line.x0 = x; + line.y0 = y; + + x = a * curve->x0 + b * ctrla->x + c * ctrlb->x + d * curve->x1; + y = a * curve->y0 + b * ctrla->y + c * ctrlb->y + d * curve->y1; + + line.x1 = x; + line.y1 = y; + + nsfb->plotter_fns->line(nsfb, &line, 1, cl, false, false); + } + + return true; +} + +static bool quadratic(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_colour_t cl) +{ + nsfb_bbox_t line; + + unsigned int seg_loop; + double t; + double one_minus_t; + double a; + double b; + double c; + double x; + double y; + + x = curve->x0; + y = curve->y0; + + for (seg_loop = 1; seg_loop <= N_SEG; ++seg_loop) { + t = (double)seg_loop / (double)N_SEG; + + one_minus_t = 1.0 - t; + + a = one_minus_t * one_minus_t; + b = 2.0 * t * one_minus_t; + c = t * t; + + line.x0 = x; + line.y0 = y; + + x = a * curve->x0 + b * ctrla->x + c * curve->x1; + y = a * curve->y0 + b * ctrla->y + c * curve->y1; + + line.x1 = x; + line.y1 = y; + + nsfb->plotter_fns->line(nsfb, &line, 1, cl, false, false); + } + + return true; +} + bool select_plotters(nsfb_t *nsfb) { const nsfb_plotter_fns_t *table; @@ -550,6 +636,8 @@ bool select_plotters(nsfb_t *nsfb) nsfb->plotter_fns->ellipse_fill = ellipse_fill; nsfb->plotter_fns->copy = copy; nsfb->plotter_fns->arc = arc; + nsfb->plotter_fns->quadratic = quadratic; + nsfb->plotter_fns->cubic = cubic; /* set default clip rectangle to size of framebuffer */ nsfb->clip.x0 = 0; diff --git a/test/Makefile b/test/Makefile index 6d4f4fa..dcb3d8f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,3 +1,3 @@ -DIR_TEST_ITEMS := plottest:plottest.c;nsglobe.c frontend:frontend.c +DIR_TEST_ITEMS := plottest:plottest.c;nsglobe.c frontend:frontend.c bezier:bezier.c include build/makefiles/Makefile.subdir diff --git a/test/bezier.c b/test/bezier.c new file mode 100644 index 0000000..d44779b --- /dev/null +++ b/test/bezier.c @@ -0,0 +1,112 @@ +/* libnsfb plotetr test program */ + +#include +#include +#include + +#include "libnsfb.h" +#include "libnsfb_plot.h" +#include "libnsfb_event.h" + +#define UNUSED(x) ((x) = (x)) + + +int main(int argc, char **argv) +{ + nsfb_t *nsfb; + nsfb_event_t event; + nsfb_bbox_t box; + nsfb_bbox_t box2; + uint8_t *fbptr; + int fbstride; + nsfb_point_t ctrla; + nsfb_point_t ctrlb; + int loop; + + UNUSED(argc); + UNUSED(argv); + + nsfb = nsfb_init(NSFB_FRONTEND_SDL); + if (nsfb == NULL) { + fprintf(stderr, "Unable to initialise nsfb with SDL frontend\n"); + return 1; + } + + if (nsfb_init_frontend(nsfb) == -1) { + fprintf(stderr, "Unable to initialise nsfb frontend\n"); + return 2; + } + + /* get the geometry of the whole screen */ + box.x0 = box.y0 = 0; + nsfb_get_geometry(nsfb, &box.x1, &box.y1, NULL); + + nsfb_get_framebuffer(nsfb, &fbptr, &fbstride); + + /* claim the whole screen for update */ + nsfb_claim(nsfb, &box); + + nsfb_plot_clg(nsfb, 0xffffffff); + + box2.x0=100; + box2.y0=100; + + box2.x1=400; + box2.y1=400; + + for (loop=-300;loop < 600;loop+=100) { + ctrla.x = 100; + ctrla.y = loop; + + ctrlb.x = 400; + ctrlb.y = 500 - loop; + + nsfb_plot_cubic_bezier(nsfb, &box2, &ctrla, &ctrlb, 0xff000000); + } + + + box2.x0=400; + box2.y0=100; + + box2.x1=600; + box2.y1=400; + + nsfb_plot_line(nsfb, &box2, 1, 0xff000000, false, false); + + box2.x0=800; + box2.y0=100; + + box2.x1=600; + box2.y1=400; + + nsfb_plot_line(nsfb, &box2, 1, 0xff000000, false, false); + + box2.x0=400; + box2.y0=100; + + box2.x1=800; + box2.y1=100; + + ctrla.x = 600; + ctrla.y = 400; + + nsfb_plot_cubic_bezier(nsfb, &box2, &ctrla, &ctrla, 0xffff0000); + + box2.x0=400; + box2.y0=100; + + box2.x1=800; + box2.y1=100; + + ctrla.x = 600; + ctrla.y = 400; + + nsfb_plot_quadratic_bezier(nsfb, &box2, &ctrla, 0xff0000ff); + + nsfb_update(nsfb, &box); + + while (event.type != NSFB_EVENT_CONTROL) + nsfb_event(nsfb, &event, -1); + + return 0; +} -- cgit v1.2.3