Graphics primitives

BY Malcolm McLean Homepage

Here are some graphics primitives routines.

They are not particularly well-optimised. However the routines will give fairly high quality results, with alpha-blending and anti-aliasing. Polygons can be of arbitrary shape.

  • graphicssupport.h
  • graphicssupport.c

    line

    An efficent integer-only line drawing algorithm is surprisingly complicated. Do a web search for Bresenham's Algorithm .

    This offering simply draws a one-pixel wide line by taking pixel steps on the major axis. However it is necessary to clip the lines to the viewport to prevent the function taking forever when called with huge values.

    /* draws a 1-pixel wide line Parmas: rgba - output raster, 32 bit rgba format width - image width height - image height x1, y1 - first point x,y coordinates x2, y2 - secondpoint xy coordiantes col - line colour, 32 bit rgba format Returns: 0 */ int line(unsigned char *rgba, int width, int height, double x1, double y1, double x2, double y2, unsigned char *col);

    Anti-aliased lines

    This draws an anti-aliased line of any width.
    It is simply an interface to the polygonaa function.
    For another approach see Wu's algorithm

    /* draws a line with anti-aliasing Parmas: rgba - output raster, 32 bit rgba format width - image width height - image height x1, y1 - first point x,y coordinates x2, y2 - secondpoint xy coordiantes lwidth - line width col - line colour, 32 bit rgba format Returns: 0 on success, -1 on fail Notes: convenience wrapper function for polygonaa */ int lineaa(unsigned char *rgba, int width, int height, double x1, double y1, double x2, double y2, double lwidth, unsigned char *col)

    rectangle

    A axis-aligned rectangle drawer is about the simplest graphics function to write. Again, you must remeber to clip to the viewport. /* draw an axis-aligned rectangle Params: rgba - output raster width - image width height - image height x1, y1 - first corner x2, y2 - second corner col - rectangle colour Returns: 0 */ int rectangle(unsigned char *rgba, int width, int height, double x1, double y1, double x2, double y2, unsigned char *col)

    circle

    Circles are similarly simple. This function just draws the bounding rectangle and fills in points within a given distance squared of the centre. This is to avoid a square root call. /* draw a circle (no anti-aliasing) Parmas: rgba - output raster width - image width height -image height x, y - circle centre r - radius col - circle coolour 32 it rgba format Returns: 0; */ int circle(unsigned char *rgba, int width, int height, double x, double y, double r, unsigned char *col)

    polygon

    Concave polygons can be draw efficiently using scanline techniques. When polygons are allowed to be concave, things are a bit more difficult.

    For each raster line, we can easily find the segments that cross it by checking for a segment that is has a y value on each side of the line. Lines parallel to the x axis, which in practise are likely to be given to the routine quite often, can simply be ignored.

    The intercepts are then calcualted, and sorted. A bubble sort is used. In practise real users will call the function with relatively simple polygons, and a bubble sort avoids the overhead of qsort and is faster for short lists.

    Each segement is then alternately inside and outside the polygon. So we simply scan through, filling in the pixels. Again we have to clip to the viewport.

    /* draw a polygon Parmas: rgba - output raster width - image width height - image height x - points x co-ordiantes y - points y co-ordinates N - number of points col - colour, 32 bit rgba format Returns: 0 on success, -1 on fail */ int polygon(unsigned char *rgba, int width, int height, double *x, double *y, int N, unsigned char *col)

    polygonaa

    The flagship of the file is the anti-aliased polygon function. Code is virtually identical to the polygon function, except that the polygon is drawn at 4* resolution and then reduced to obtain the alphas.

    If the polygon is going to be further processed, or you have a limited palette, then generally you will want to call the non-anti-aliased function because edge pixels are blended. If the polygon is to be viewed directly, then the anti-aliased routine will give better quality.

    There are more efficient ways of doing things, but they tend to be complex because the corner pixels need to be treated as special cases.

    /* draw an anti-aliased polygon Parmas: rgba - output raster width - image width height - image height x - points x co-ordiantes y - points y co-ordinates N - number of points col - colour, 32 bit rgba format Returns: 0 on success, -1 on fail */ int polygonaa(unsigned char *rgba, int width, int height, double *x, double *y, int N, unsigned char *col)