Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
  3.  * Copyright 2009 Michael Drake <tlsa@netsurf-browser.org>
  4.  *
  5.  * This file is part of libnsfb, http://www.netsurf-browser.org/
  6.  * Licenced under the MIT License,
  7.  *                http://www.opensource.org/licenses/mit-license.php
  8.  */
  9.  
  10. /** \file
  11.  * generic plotter functions which are not depth dependant (implementation).
  12.  */
  13.  
  14. #include <stdbool.h>
  15. #include <limits.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include "libnsfb.h"
  20. #include "libnsfb_plot.h"
  21. #include "libnsfb_plot_util.h"
  22.  
  23. #include "nsfb.h"
  24. #include "plot.h"
  25. #include "surface.h"
  26.  
  27. extern const nsfb_plotter_fns_t _nsfb_1bpp_plotters;
  28. extern const nsfb_plotter_fns_t _nsfb_8bpp_plotters;
  29. extern const nsfb_plotter_fns_t _nsfb_16bpp_plotters;
  30. extern const nsfb_plotter_fns_t _nsfb_24bpp_plotters;
  31. extern const nsfb_plotter_fns_t _nsfb_32bpp_xrgb8888_plotters;
  32. extern const nsfb_plotter_fns_t _nsfb_32bpp_xbgr8888_plotters;
  33.  
  34. static bool set_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
  35. {
  36.     nsfb_bbox_t fbarea;
  37.  
  38.     /* screen area */
  39.     fbarea.x0 = 0;
  40.     fbarea.y0 = 0;
  41.     fbarea.x1 = nsfb->width;
  42.     fbarea.y1 = nsfb->height;
  43.  
  44.     if (clip == NULL) {
  45.         nsfb->clip = fbarea;
  46.     } else {
  47.         if (!nsfb_plot_clip(&fbarea, clip))
  48.             return false;
  49.  
  50.         nsfb->clip = *clip;
  51.     }
  52.     return true;
  53. }
  54.  
  55. static bool get_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
  56. {
  57.     *clip = nsfb->clip;
  58.     return true;
  59. }
  60.  
  61. static bool clg(nsfb_t *nsfb, nsfb_colour_t c)
  62. {
  63.     return nsfb->plotter_fns->fill(nsfb, &nsfb->clip, c);
  64. }
  65.  
  66. /**
  67.  * Establish whether there is any value in a line's crossing.
  68.  * (Helper function for find_span().)
  69.  *
  70.  * \param  x     x coordinate of intersection
  71.  * \param  y     current y level
  72.  * \param  x0    line start coordinate
  73.  * \param  y0    line start coordinate
  74.  * \param  x1    line end coordinate
  75.  * \param  y1    line end coordinate
  76.  * \return true  if crossing has value
  77.  *
  78.  *                         +            |                             | /
  79.  *                        /             |                             |/
  80.  *   y level --      ----/----      ----+----      ----+----      ----+----
  81.  *                      /              /              /|
  82.  *                     +             /               / |
  83.  *
  84.  *                      (a)            (b)            (c)            (d)
  85.  *
  86.  *
  87.  * Figure (a) values:  1     = 1  --  Odd  -- Valid crossing
  88.  * Figure (b) values:  0 + 1 = 1  --  Odd  -- Valid crossing
  89.  * Figure (c) values:  1 + 1 = 2  --  Even -- Not valid crossing
  90.  * Figure (d) values:  0 + 0 = 0  --  Even -- Not valid crossing
  91.  *
  92.  * Vertices are shared between consecutive lines.  This function ensures that
  93.  * the vertex point is only counted as a crossing for one of the lines by
  94.  * only considering crossings of the top vertex.  This is what NetSurf's
  95.  * plotter API expects.
  96.  *
  97.  * It's up to the client to call this function for both lines and check the
  98.  * evenness of the total.
  99.  */
  100. static bool establish_crossing_value(int x, int y, int x0, int y0,
  101.                                      int x1, int y1)
  102. {
  103.     bool v1 = (x == x0 && y == y0); /* whether we're crossing 1st vertex */
  104.     bool v2 = (x == x1 && y == y1); /* whether we're crossing 2nd vertex */
  105.  
  106.     if ((v1 && (y0 < y1)) || (v2 && (y1 < y0))) {
  107.         /* crossing top vertex */
  108.         return true;
  109.     } else if (!v1 && !v2) {
  110.         /* Intersection with current y level is not at a vertex.
  111.          * Normal crossing. */
  112.         return true;
  113.     }
  114.     return false;
  115. }
  116.  
  117.  
  118. /**
  119.  * Find first filled span along horizontal line at given coordinate
  120.  *
  121.  * \param  p     array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
  122.  * \param  n     number of polygon vertex values (N * 2)
  123.  * \param  x     current position along current scan line
  124.  * \param  y     position of current scan line
  125.  * \param  x0    updated to start of filled area
  126.  * \param  x1    updated to end of filled area
  127.  * \return true  if an intersection was found
  128.  */
  129. static bool find_span(const int *p, int n, int x, int y, int *x0, int *x1)
  130. {
  131.     int i;
  132.     int p_x0, p_y0;
  133.     int p_x1, p_y1;
  134.     int x0_min, x1_min;
  135.     int x_new;
  136.     unsigned int x0c, x1c; /* counters for crossings at span end points */
  137.     bool crossing_value;
  138.     bool found_span_start = false;
  139.  
  140.     x0_min = x1_min = INT_MIN;
  141.     x0c = x1c = 0;
  142.     *x0 = *x1 = INT_MAX;
  143.  
  144.     /* search row for next span, returning it if one exists */
  145.     do {
  146.         /* reset endpoint info, if valid span endpoints not found */
  147.         if (!found_span_start)
  148.             *x0 = INT_MAX;
  149.         *x1 = INT_MAX;
  150.  
  151.         /* search all lines in polygon */
  152.         for (i = 0; i < n; i = i + 2) {
  153.             /* get line endpoints */
  154.             if (i != n - 2) {
  155.                 /* not the last line */
  156.                 p_x0 = p[i];            p_y0 = p[i + 1];
  157.                 p_x1 = p[i + 2];        p_y1 = p[i + 3];
  158.             } else {
  159.                 /* last line; 2nd endpoint is first vertex */
  160.                 p_x0 = p[i];            p_y0 = p[i + 1];
  161.                 p_x1 = p[0];            p_y1 = p[1];
  162.             }
  163.             /* ignore horizontal lines */
  164.             if (p_y0 == p_y1)
  165.                 continue;
  166.  
  167.             /* ignore lines that don't cross this y level */
  168.             if ((y < p_y0 && y < p_y1) || (y > p_y0 && y > p_y1))
  169.                 continue;
  170.  
  171.             if (p_x0 == p_x1) {
  172.                 /* vertical line, x is constant */
  173.                 x_new = p_x0;
  174.             } else {
  175.                 /* find crossing (intersection of this line and
  176.                  * current y level) */
  177.                 int num = (y - p_y0) * (p_x1 - p_x0);
  178.                 int den = (p_y1 - p_y0);
  179.  
  180.                 /* To round to nearest (rather than down)
  181.                  * half the denominator is either added to
  182.                  * or subtracted from the numerator,
  183.                  * depending on whether the numerator and
  184.                  * denominator have the same sign. */
  185.                 num = ((num < 0) == (den < 0)) ?
  186.                     num + (den / 2) :
  187.                     num - (den / 2);
  188.                 x_new = p_x0 + num / den;
  189.             }
  190.  
  191.             /* ignore crossings before current x */
  192.             if (x_new < x ||
  193.                 (!found_span_start && x_new < x0_min) ||
  194.                 (found_span_start && x_new < x1_min))
  195.                 continue;
  196.  
  197.             crossing_value = establish_crossing_value(x_new, y,
  198.                                                       p_x0, p_y0, p_x1, p_y1);
  199.  
  200.  
  201.             /* set nearest intersections as filled area endpoints */
  202.             if (!found_span_start &&
  203.                 x_new < *x0 && crossing_value) {
  204.                 /* nearer than first endpoint */
  205.                 *x1 = *x0;
  206.                 x1c = x0c;
  207.                 *x0 = x_new;
  208.                 x0c = 1;
  209.             } else if (!found_span_start &&
  210.                        x_new == *x0 && crossing_value) {
  211.                 /* same as first endpoint */
  212.                 x0c++;
  213.             } else if (x_new < *x1 && crossing_value) {
  214.                 /* nearer than second endpoint */
  215.                 *x1 = x_new;
  216.                 x1c = 1;
  217.             } else if (x_new == *x1 && crossing_value) {
  218.                 /* same as second endpoint */
  219.                 x1c++;
  220.             }
  221.         }
  222.         /* check whether the span endpoints have been found */
  223.         if (!found_span_start && x0c % 2 == 1) {
  224.             /* valid fill start found */
  225.             found_span_start = true;
  226.  
  227.         }
  228.         if (x1c % 2 == 1) {
  229.             /* valid fill endpoint found */
  230.             if (!found_span_start) {
  231.                 /* not got a start yet; use this as start */
  232.                 found_span_start = true;
  233.                 x0c = x1c;
  234.                 *x0 = *x1;
  235.             } else {
  236.                 /* got valid end of span */
  237.                 return true;
  238.             }
  239.         }
  240.         /* if current positions aren't valid endpoints, set new
  241.          * minimums after current positions */
  242.         if (!found_span_start)
  243.             x0_min = *x0 + 1;
  244.         x1_min = *x1 + 1;
  245.  
  246.     } while (*x1 != INT_MAX);
  247.  
  248.     /* no spans found */
  249.     return false;
  250. }
  251.  
  252.  
  253. /**
  254.  * Plot a polygon
  255.  *
  256.  * \param  nsfb  framebuffer context
  257.  * \param  p     array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
  258.  * \param  n     number of polygon vertices (N)
  259.  * \param  c     fill colour
  260.  * \return true  if no errors
  261.  */
  262. static bool polygon(nsfb_t *nsfb, const int *p, unsigned int n, nsfb_colour_t c)
  263. {
  264.     int poly_x0, poly_y0; /* Bounding box top left corner */
  265.     int poly_x1, poly_y1; /* Bounding box bottom right corner */
  266.     int i, j; /* indexes */
  267.     int x0, x1; /* filled span extents */
  268.     int y; /* current y coordinate */
  269.     int y_max; /* bottom of plot area */
  270.     nsfb_bbox_t fline;
  271.     nsfb_plot_pen_t pen;
  272.  
  273.     /* find no. of vertex values */
  274.     int v = n * 2;
  275.  
  276.     /* Can't plot polygons with 2 or fewer vertices */
  277.     if (n <= 2)
  278.         return true;
  279.  
  280.     pen.stroke_colour = c;
  281.  
  282.     /* Find polygon bounding box */
  283.     poly_x0 = poly_x1 = *p;
  284.     poly_y0 = poly_y1 = p[1];
  285.     for (i = 2; i < v; i = i + 2) {
  286.         j = i + 1;
  287.         if (p[i] < poly_x0)
  288.             poly_x0 = p[i];
  289.         else if (p[i] > poly_x1)
  290.             poly_x1 = p[i];
  291.         if (p[j] < poly_y0)
  292.             poly_y0 = p[j];
  293.         else if (p[j] > poly_y1)
  294.             poly_y1 = p[j];
  295.     }
  296.  
  297.     /* Don't try to plot it if it's outside the clip rectangle */
  298.     if (nsfb->clip.y1 < poly_y0 ||
  299.         nsfb->clip.y0 > poly_y1 ||
  300.         nsfb->clip.x1 < poly_x0 ||
  301.         nsfb->clip.x0 > poly_x1)
  302.         return true;
  303.  
  304.     /* Find the top of the important area */
  305.     if (poly_y0 > nsfb->clip.y0)
  306.         y = poly_y0;
  307.     else
  308.         y = nsfb->clip.y0;
  309.  
  310.     /* Find the bottom of the important area */
  311.     if (poly_y1 < nsfb->clip.y1)
  312.         y_max = poly_y1;
  313.     else
  314.         y_max = nsfb->clip.y1;
  315.  
  316.     for (; y < y_max; y++) {
  317.         x1 = poly_x0 - 1;
  318.         /* For each row */
  319.         while (find_span(p, v, x1 + 1, y, &x0, &x1)) {
  320.             /* don't draw anything outside clip region */
  321.             if (x1 < nsfb->clip.x0)
  322.                 continue;
  323.             else if (x0 < nsfb->clip.x0)
  324.                 x0 = nsfb->clip.x0;
  325.             if (x0 > nsfb->clip.x1)
  326.                 break;
  327.             else if (x1 > nsfb->clip.x1)
  328.                 x1 = nsfb->clip.x1;
  329.  
  330.             fline.x0 = x0;
  331.             fline.y0 = y;
  332.             fline.x1 = x1;
  333.             fline.y1 = y;
  334.  
  335.             /* draw this filled span on current row */
  336.             nsfb->plotter_fns->line(nsfb, 1, &fline, &pen);
  337.  
  338.             /* don't look for more spans if already at end of clip
  339.              * region or polygon */
  340.             if (x1 == nsfb->clip.x1 || x1 == poly_x1)
  341.                 break;
  342.         }
  343.     }
  344.     return true;
  345. }
  346.  
  347. static bool
  348. rectangle(nsfb_t *nsfb, nsfb_bbox_t *rect,
  349.           int line_width, nsfb_colour_t c,
  350.           bool dotted, bool dashed)
  351. {
  352.     nsfb_bbox_t side[4];
  353.     nsfb_plot_pen_t pen;
  354.  
  355.     pen.stroke_colour = c;
  356.     pen.stroke_width = line_width;
  357.     if (dotted || dashed) {
  358.         pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
  359.     } else {
  360.         pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
  361.     }
  362.  
  363.     side[0] = *rect;
  364.     side[1] = *rect;
  365.     side[2] = *rect;
  366.     side[3] = *rect;
  367.  
  368.     side[0].y1 = side[0].y0;
  369.     side[1].y0 = side[1].y1;
  370.     side[2].x1 = side[2].x0;
  371.     side[3].x0 = side[3].x1;
  372.  
  373.     return nsfb->plotter_fns->line(nsfb, 4, side, &pen);
  374. }
  375.  
  376. /* plotter routine for ellipse points */
  377. static void
  378. ellipsepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
  379. {
  380.     nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c);
  381.     nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c);
  382.     nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c);
  383.     nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c);
  384. }
  385.  
  386. static void
  387. ellipsefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
  388. {
  389.     nsfb_bbox_t fline[2];
  390.     nsfb_plot_pen_t pen;
  391.  
  392.     pen.stroke_colour = c;
  393.  
  394.     fline[0].x0 = fline[1].x0 = cx - x;
  395.     fline[0].x1 = fline[1].x1 = cx + x;
  396.     fline[0].y0 = fline[0].y1 = cy + y;
  397.     fline[1].y0 = fline[1].y1 = cy - y;
  398.  
  399.     nsfb->plotter_fns->line(nsfb, 2, fline, &pen);
  400.  
  401. }
  402.  
  403. #define ROUND(a) ((int)(a+0.5))
  404.  
  405. static bool
  406. ellipse_midpoint(nsfb_t *nsfb,
  407.                  int cx,
  408.                  int cy,
  409.                  int rx,
  410.                  int ry,
  411.                  nsfb_colour_t c,
  412.                  void (ellipsefn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c))
  413. {
  414.     int rx2 = rx * rx;
  415.     int ry2 = ry * ry;
  416.     int tworx2 = 2 * rx2;
  417.     int twory2 = 2 * ry2;
  418.     int p;
  419.     int x = 0;
  420.     int y = ry;
  421.     int px = 0;
  422.     int py = tworx2 * y;
  423.  
  424.     ellipsefn(nsfb, cx, cy, x, y, c);
  425.  
  426.     /* region 1 */
  427.     p = ROUND(ry2 - (rx2 * ry) + (0.25 * rx2));
  428.     while (px < py) {
  429.         x++;
  430.         px += twory2;
  431.         if (p <0) {
  432.             p+=ry2 + px;
  433.         } else {
  434.             y--;
  435.             py -= tworx2;
  436.             p+=ry2 + px - py;
  437.         }
  438.         ellipsefn(nsfb, cx, cy, x, y, c);
  439.     }
  440.  
  441.     /* region 2 */
  442.     p = ROUND(ry2*(x+0.5)*(x+0.5) + rx2*(y-1)*(y-1) - rx2*ry2);
  443.     while (y > 0) {
  444.         y--;
  445.         py -= tworx2;
  446.         if (p > 0) {
  447.             p+=rx2 - py;
  448.         } else {
  449.             x++;
  450.             px += twory2;
  451.             p+=rx2 - py + px;
  452.         }
  453.         ellipsefn(nsfb, cx, cy, x, y, c);
  454.     }
  455.     return true;
  456. }
  457.  
  458.  
  459. /* plotter routine for 8way circle symetry */
  460. static void
  461. circlepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
  462. {
  463.     nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c);
  464.     nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c);
  465.     nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c);
  466.     nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c);
  467.     nsfb->plotter_fns->point(nsfb, cx + y, cy + x, c);
  468.     nsfb->plotter_fns->point(nsfb, cx - y, cy + x, c);
  469.     nsfb->plotter_fns->point(nsfb, cx + y, cy - x, c);
  470.     nsfb->plotter_fns->point(nsfb, cx - y, cy - x, c);
  471. }
  472.  
  473. static void
  474. circlefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
  475. {
  476.     nsfb_bbox_t fline[4];
  477.     nsfb_plot_pen_t pen;
  478.  
  479.     pen.stroke_colour = c;
  480.  
  481.     fline[0].x0 = fline[1].x0 = cx - x;
  482.     fline[0].x1 = fline[1].x1 = cx + x;
  483.     fline[0].y0 = fline[0].y1 = cy + y;
  484.     fline[1].y0 = fline[1].y1 = cy - y;
  485.  
  486.     fline[2].x0 = fline[3].x0 = cx - y;
  487.     fline[2].x1 = fline[3].x1 = cx + y;
  488.     fline[2].y0 = fline[2].y1 = cy + x;
  489.     fline[3].y0 = fline[3].y1 = cy - x;
  490.  
  491.     nsfb->plotter_fns->line(nsfb, 4, fline, &pen);
  492. }
  493.  
  494. static bool circle_midpoint(nsfb_t *nsfb,
  495.                             int cx,
  496.                             int cy,
  497.                             int r,
  498.                             nsfb_colour_t c,
  499.                             void (circfn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c))
  500. {
  501.     int x = 0;
  502.     int y = r;
  503.     int p = 1 - r;
  504.  
  505.     circfn(nsfb, cx, cy, x, y, c);
  506.     while (x < y) {
  507.         x++;
  508.         if (p < 0) {
  509.             p += 2 * x + 1;
  510.         } else {
  511.             y--;
  512.             p += 2 * (x - y) + 1;
  513.         }
  514.         circfn(nsfb, cx, cy, x, y, c);
  515.     }
  516.     return true;
  517. }
  518.  
  519. static bool ellipse(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
  520. {
  521.     int width = (ellipse->x1 - ellipse->x0)>>1;
  522.     int height = (ellipse->y1 - ellipse->y0)>>1;
  523.  
  524.     if (width == height) {
  525.         /* circle */
  526.         return circle_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, c, circlepoints);
  527.     } else {
  528.         return ellipse_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, height, c, ellipsepoints);
  529.     }
  530. }
  531.  
  532. static bool ellipse_fill(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
  533. {
  534.     int width = (ellipse->x1 - ellipse->x0) >> 1;
  535.     int height = (ellipse->y1 - ellipse->y0) >> 1;
  536.  
  537.     if (width == height) {
  538.         /* circle */
  539.         return circle_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, c, circlefill);
  540.     } else {
  541.         return ellipse_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, height, c, ellipsefill);
  542.     }
  543. }
  544.  
  545.  
  546.  
  547. /* copy an area of surface from one location to another.
  548.  *
  549.  * @warning This implementation is woefully incomplete!
  550.  */
  551. static bool
  552. copy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
  553. {
  554.     int srcx = srcbox->x0;
  555.     int srcy = srcbox->y0;
  556.     int dstx = dstbox->x0;
  557.     int dsty = dstbox->y0;
  558.     int width = dstbox->x1 - dstbox->x0;
  559.     int height = dstbox->y1 - dstbox->y0;
  560.     uint8_t *srcptr;
  561.     uint8_t *dstptr;
  562.     int hloop;
  563.     nsfb_bbox_t allbox;
  564.  
  565.     nsfb_plot_add_rect(srcbox, dstbox, &allbox);
  566.  
  567.     nsfb->surface_rtns->claim(nsfb, &allbox);
  568.  
  569.     srcptr = (nsfb->ptr +
  570.               (srcy * nsfb->linelen) +
  571.               ((srcx * nsfb->bpp) / 8));
  572.  
  573.     dstptr = (nsfb->ptr +
  574.               (dsty * nsfb->linelen) +
  575.               ((dstx * nsfb->bpp) / 8));
  576.  
  577.  
  578.     if (width == nsfb->width) {
  579.         /* take shortcut and use memmove */
  580.         memmove(dstptr, srcptr, (width * height * nsfb->bpp) / 8);
  581.     } else {
  582.         if (srcy > dsty) {
  583.             for (hloop = height; hloop > 0; hloop--) {
  584.                 memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
  585.                 srcptr += nsfb->linelen;
  586.                 dstptr += nsfb->linelen;
  587.             }
  588.         } else {
  589.             srcptr += height * nsfb->linelen;
  590.             dstptr += height * nsfb->linelen;
  591.             for (hloop = height; hloop > 0; hloop--) {
  592.                 srcptr -= nsfb->linelen;
  593.                 dstptr -= nsfb->linelen;
  594.                 memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
  595.             }
  596.         }
  597.     }
  598.  
  599.     nsfb->surface_rtns->update(nsfb, dstbox);
  600.  
  601.     return true;
  602. }
  603.  
  604.  
  605.  
  606. static bool arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, int angle2, nsfb_colour_t c)
  607. {
  608.     nsfb=nsfb;
  609.     x = x;
  610.     y = y;
  611.     radius = radius;
  612.     c = c;
  613.     angle1=angle1;
  614.     angle2=angle2;
  615.     return true;
  616. }
  617.  
  618. #define N_SEG 30
  619.  
  620. static int
  621. cubic_points(unsigned int pointc,
  622.              nsfb_point_t *point,
  623.              nsfb_bbox_t *curve,
  624.              nsfb_point_t *ctrla,
  625.              nsfb_point_t *ctrlb)
  626. {
  627.     unsigned int seg_loop;
  628.     double t;
  629.     double one_minus_t;
  630.     double a;
  631.     double b;
  632.     double c;
  633.     double d;
  634.     double x;
  635.     double y;
  636.     int cur_point;
  637.  
  638.     point[0].x = curve->x0;
  639.     point[0].y = curve->y0;
  640.     cur_point = 1;
  641.     pointc--;
  642.  
  643.     for (seg_loop = 1; seg_loop < pointc; ++seg_loop) {
  644.         t = (double)seg_loop / (double)pointc;
  645.  
  646.         one_minus_t = 1.0 - t;
  647.  
  648.         a = one_minus_t * one_minus_t * one_minus_t;
  649.         b = 3.0 * t * one_minus_t * one_minus_t;
  650.         c = 3.0 * t * t * one_minus_t;
  651.         d = t * t * t;
  652.  
  653.         x = a * curve->x0 + b * ctrla->x + c * ctrlb->x + d * curve->x1;
  654.         y = a * curve->y0 + b * ctrla->y + c * ctrlb->y + d * curve->y1;
  655.  
  656.         point[cur_point].x = x;
  657.         point[cur_point].y = y;
  658.         if ((point[cur_point].x != point[cur_point - 1].x) ||
  659.             (point[cur_point].y != point[cur_point - 1].y))
  660.             cur_point++;
  661.     }
  662.  
  663.     point[cur_point].x = curve->x1;
  664.     point[cur_point].y = curve->y1;
  665.     if ((point[cur_point].x != point[cur_point - 1].x) ||
  666.         (point[cur_point].y != point[cur_point - 1].y))
  667.         cur_point++;
  668.  
  669.     return cur_point;
  670. }
  671.  
  672. /* calculate a series of points which describe a quadratic bezier spline.
  673.  *
  674.  * fills an array of points with values describing a quadratic curve. Both the
  675.  * start and end points are included as the first and last points
  676.  * respectively. Only if the next point on the curve is different from its
  677.  * predecessor is the point added which ensures points for the same position
  678.  * are not repeated.
  679.  */
  680. static int
  681. quadratic_points(unsigned int pointc,
  682.                  nsfb_point_t *point,
  683.                  nsfb_bbox_t *curve,
  684.                  nsfb_point_t *ctrla)
  685. {
  686.     unsigned int seg_loop;
  687.     double t;
  688.     double one_minus_t;
  689.     double a;
  690.     double b;
  691.     double c;
  692.     double x;
  693.     double y;
  694.     int cur_point;
  695.  
  696.     point[0].x = curve->x0;
  697.     point[0].y = curve->y0;
  698.     cur_point = 1;
  699.     pointc--; /* we have added the start point, one less point in the curve */
  700.  
  701.     for (seg_loop = 1; seg_loop < pointc; ++seg_loop) {
  702.         t = (double)seg_loop / (double)pointc;
  703.  
  704.         one_minus_t = 1.0 - t;
  705.  
  706.         a = one_minus_t * one_minus_t;
  707.         b = 2.0 * t * one_minus_t;
  708.         c = t * t;
  709.  
  710.         x = a * curve->x0 + b * ctrla->x + c * curve->x1;
  711.         y = a * curve->y0 + b * ctrla->y + c * curve->y1;
  712.  
  713.         point[cur_point].x = x;
  714.         point[cur_point].y = y;
  715.         if ((point[cur_point].x != point[cur_point - 1].x) ||
  716.             (point[cur_point].y != point[cur_point - 1].y))
  717.             cur_point++;
  718.     }
  719.  
  720.     point[cur_point].x = curve->x1;
  721.     point[cur_point].y = curve->y1;
  722.     if ((point[cur_point].x != point[cur_point - 1].x) ||
  723.         (point[cur_point].y != point[cur_point - 1].y))
  724.         cur_point++;
  725.  
  726.     return cur_point;
  727. }
  728.  
  729. static bool
  730. polylines(nsfb_t *nsfb,
  731.           int pointc,
  732.           const nsfb_point_t *points,
  733.           nsfb_plot_pen_t *pen)
  734. {
  735.     int point_loop;
  736.     nsfb_bbox_t line;
  737.  
  738.     if (pen->stroke_type != NFSB_PLOT_OPTYPE_NONE) {
  739.         for (point_loop = 0; point_loop < (pointc - 1); point_loop++) {
  740.             line = *(nsfb_bbox_t *)&points[point_loop];
  741.             nsfb->plotter_fns->line(nsfb, 1, &line, pen);
  742.         }
  743.     }
  744.     return true;
  745. }
  746.  
  747.  
  748.  
  749. static bool
  750. quadratic(nsfb_t *nsfb,
  751.           nsfb_bbox_t *curve,
  752.           nsfb_point_t *ctrla,
  753.           nsfb_plot_pen_t *pen)
  754. {
  755.     nsfb_point_t points[N_SEG];
  756.  
  757.     if (pen->stroke_type == NFSB_PLOT_OPTYPE_NONE)
  758.         return false;
  759.  
  760.     return polylines(nsfb, quadratic_points(N_SEG, points, curve, ctrla), points, pen);
  761. }
  762.  
  763. static bool
  764. cubic(nsfb_t *nsfb,
  765.       nsfb_bbox_t *curve,
  766.       nsfb_point_t *ctrla,
  767.       nsfb_point_t *ctrlb,
  768.       nsfb_plot_pen_t *pen)
  769. {
  770.     nsfb_point_t points[N_SEG];
  771.  
  772.     if (pen->stroke_type == NFSB_PLOT_OPTYPE_NONE)
  773.         return false;
  774.  
  775.     return polylines(nsfb, cubic_points(N_SEG, points, curve, ctrla,ctrlb), points, pen);
  776. }
  777.  
  778.  
  779. static bool
  780. path(nsfb_t *nsfb, int pathc, nsfb_plot_pathop_t *pathop, nsfb_plot_pen_t *pen)
  781. {
  782.     int path_loop;
  783.     nsfb_point_t *pts;
  784.     nsfb_point_t *curpt;
  785.     int ptc = 0;
  786.     nsfb_bbox_t curve;
  787.     nsfb_point_t ctrla;
  788.     nsfb_point_t ctrlb;
  789.     int added_count = 0;
  790.     int bpts;
  791.  
  792.     /* count the verticies in the path and add N_SEG extra for curves */
  793.     for (path_loop = 0; path_loop < pathc; path_loop++) {
  794.         ptc++;
  795.         if ((pathop[path_loop].operation == NFSB_PLOT_PATHOP_QUAD) ||
  796.             (pathop[path_loop].operation == NFSB_PLOT_PATHOP_CUBIC))
  797.             ptc += N_SEG;
  798.     }
  799.  
  800.     /* allocate storage for the vertexes */
  801.     curpt = pts = malloc(ptc * sizeof(nsfb_point_t));
  802.  
  803.     for (path_loop = 0; path_loop < pathc; path_loop++) {
  804.         switch (pathop[path_loop].operation) {
  805.         case NFSB_PLOT_PATHOP_QUAD:
  806.             curpt-=2;
  807.             added_count -= 2;
  808.             curve.x0 = pathop[path_loop - 2].point.x;
  809.             curve.y0 = pathop[path_loop - 2].point.y;
  810.             ctrla.x = pathop[path_loop - 1].point.x;
  811.             ctrla.y = pathop[path_loop - 1].point.y;
  812.             curve.x1 = pathop[path_loop].point.x;
  813.             curve.y1 = pathop[path_loop].point.y;
  814.             bpts = quadratic_points(N_SEG, curpt, &curve, &ctrla);
  815.             curpt += bpts;
  816.             added_count += bpts;
  817.             break;
  818.  
  819.         case NFSB_PLOT_PATHOP_CUBIC:
  820.             curpt-=3;
  821.             added_count -=3;
  822.             curve.x0 = pathop[path_loop - 3].point.x;
  823.             curve.y0 = pathop[path_loop - 3].point.y;
  824.             ctrla.x = pathop[path_loop - 2].point.x;
  825.             ctrla.y = pathop[path_loop - 2].point.y;
  826.             ctrlb.x = pathop[path_loop - 1].point.x;
  827.             ctrlb.y = pathop[path_loop - 1].point.y;
  828.             curve.x1 = pathop[path_loop].point.x;
  829.             curve.y1 = pathop[path_loop].point.y;
  830.             bpts = cubic_points(N_SEG, curpt, &curve, &ctrla, &ctrlb);
  831.             curpt += bpts;
  832.             added_count += bpts;
  833.             break;
  834.  
  835.         default:
  836.             *curpt = pathop[path_loop].point;
  837.             curpt++;
  838.             added_count ++;
  839.             break;
  840.         }
  841.     }
  842.  
  843.     if (pen->fill_type != NFSB_PLOT_OPTYPE_NONE) {
  844.         polygon(nsfb, (int *)pts, added_count, pen->fill_colour);
  845.     }
  846.  
  847.     if (pen->stroke_type != NFSB_PLOT_OPTYPE_NONE) {
  848.         polylines(nsfb, added_count, pts, pen);
  849.     }
  850.  
  851.     free(pts);
  852.  
  853.     return true;
  854. }
  855.  
  856. bool select_plotters(nsfb_t *nsfb)
  857. {
  858.     const nsfb_plotter_fns_t *table = NULL;
  859.  
  860.     switch (nsfb->format) {
  861.  
  862.     case NSFB_FMT_XBGR8888: /* 32bpp Unused Blue Green Red */
  863.     case NSFB_FMT_ABGR8888: /* 32bpp Alpha Blue Green Red */
  864.         table = &_nsfb_32bpp_xbgr8888_plotters;
  865.         nsfb->bpp = 32;
  866.         break;
  867.  
  868.     case NSFB_FMT_XRGB8888: /* 32bpp Unused Red Green Blue */
  869.     case NSFB_FMT_ARGB8888: /* 32bpp Alpha Red Green Blue */
  870.         table = &_nsfb_32bpp_xrgb8888_plotters;
  871.         nsfb->bpp = 32;
  872.         break;
  873.  
  874.  
  875.     case NSFB_FMT_RGB888: /* 24 bpp Alpha Red Green Blue */
  876. #ifdef ENABLE_24_BPP
  877.         table = &_nsfb_24bpp_plotters;
  878.         nsfb->bpp = 24;
  879.         break;
  880. #else
  881.         return false;
  882. #endif
  883.  
  884.     case NSFB_FMT_ARGB1555: /* 16 bpp 555 */
  885.     case NSFB_FMT_RGB565: /* 16 bpp 565 */
  886.         table = &_nsfb_16bpp_plotters;
  887.         nsfb->bpp = 16;
  888.         break;
  889.  
  890.     case NSFB_FMT_I8: /* 8bpp indexed */
  891.         table = &_nsfb_8bpp_plotters;
  892.         nsfb->bpp = 8;
  893.         break;
  894.  
  895.     case NSFB_FMT_I1: /* black and white */
  896. #ifdef ENABLE_1_BPP
  897.         table = &_nsfb_1bpp_plotters;
  898.         nsfb->bpp = 1
  899.         break; 
  900. #else
  901.         return false;
  902. #endif
  903.  
  904.     case NSFB_FMT_ANY: /* No specific format - use surface default */
  905.     default:
  906.         return false;
  907.     }
  908.  
  909.     if (nsfb->plotter_fns != NULL)
  910.         free(nsfb->plotter_fns);
  911.  
  912.     nsfb->plotter_fns = calloc(1, sizeof(nsfb_plotter_fns_t));
  913.     memcpy(nsfb->plotter_fns, table, sizeof(nsfb_plotter_fns_t));
  914.  
  915.     /* set the generics */
  916.     nsfb->plotter_fns->clg = clg;
  917.     nsfb->plotter_fns->set_clip = set_clip;
  918.     nsfb->plotter_fns->get_clip = get_clip;
  919.     nsfb->plotter_fns->polygon = polygon;
  920.     nsfb->plotter_fns->rectangle = rectangle;
  921.     nsfb->plotter_fns->ellipse = ellipse;
  922.     nsfb->plotter_fns->ellipse_fill = ellipse_fill;
  923.     nsfb->plotter_fns->copy = copy;
  924.     nsfb->plotter_fns->arc = arc;
  925.     nsfb->plotter_fns->quadratic = quadratic;
  926.     nsfb->plotter_fns->cubic = cubic;
  927.     nsfb->plotter_fns->path = path;
  928.     nsfb->plotter_fns->polylines = polylines;
  929.  
  930.     /* set default clip rectangle to size of framebuffer */
  931.     nsfb->clip.x0 = 0;
  932.     nsfb->clip.y0 = 0;
  933.     nsfb->clip.x1 = nsfb->width;
  934.     nsfb->clip.y1 = nsfb->height;
  935.  
  936.     return true;
  937. }
  938.  
  939. /*
  940.  * Local variables:
  941.  *  c-basic-offset: 4
  942.  *  tab-width: 8
  943.  * End:
  944.  */
  945.