/******************************************************************************
 * mach64 Chapter 7 sample code                                               *
 *                                                                            *
 * polygon2.c - This program uses the mach64 engine to draw polygons          *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include <stdio.h>
#include <i86.h>
#include ".\util\atim64.h"
#include ".\util\defines.h"
#include ".\util\main.h"

// Prototypes.

void draw_a_line (int x1, int y1, int x2, int y2);
void draw_a_line24 (int x1, int y1, int x2, int y2);


//  variables for timing purposes.
unsigned int startarrow, endarrow, startv, endv, startcross, endcross;
int countv, countcross, countarrow;

/******************************************************************************
 * Main Program to demonstrate line drawing for polygons                      *
 *  Function: Demonstrates mach64 engine line drawing feature.                *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void main (int argc, char *argv[])
{

    point pts[20];
    polygon poly;

    printf ("mach64 Chapter 7 sample code\n"
            "\n"
            "polygon2.c\n"
            "This program demonstrates the simple line draw function of the mach64\n"
            "engine based on the modules developed in Chapter 4 and Chapter 6.\n"
            "Spatial resolution (640, 800, 1024, 1280, 1600) and Colour Depth\n"
            "(8, 15, 16, 24, 32) should be passed as arguments.\n"
            "Default setting is 640x480 spatial resolution and 8bpp pixel depth.\n");

    // Batch command to detect the mach64, perform a hardware query, Save old
    // mode information, process mode info arguments, load and set mode, enable
    // aperture, set up palettes, initialize engine to known state, and reset
    // all engine queues.

    // Cases when Spatial resolution and/or Colour Depth is/are supported by system.    
    if (!(start (argc, argv)))
    {
        printf("\nPress any key to exit...\n");
        getch();
        finish();
        exit(1);
    }

    // Sample drawing routines.

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    // Arrow-shaped polygon pointing at North-West
    testa(1);
    getch();

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    // Arrow-shaped polygon pointing at South-West
    testa(2);
    getch();

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    // Arrow-shaped polygon pointing at South-East
    testa(3);
    getch();

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    // Arrow-shaped polygon pointing at North-East
    testa(4);
    getch();

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    //  V-shaped polygon(s) with different orientations
    testb();
    getch();

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    //  Cross-shaped polygon
    testc();
    getch();

    // Batch command to restore old mode.

    finish ();

    // Show data
    printf("Information\n");
    printf("***********\n\n");
    printf("Number of Vertices for V-shaped Polygons: 4\n");
    printf("Number of V-shaped Polygons Drawn: %u\n",countv);
    printf("Time taken to draw a V-shaped Polygon:  %lf\n",(double)((double)(endv-startv)/(double)(countv)));
    printf("\nNumber of Vertices for Arrow-shaped Polygons: 7\n");
    printf("Number of Arrow-shaped Polygons Drawn: %u\n",countarrow);
    printf("Time taken to draw a arrow-shaped Polygon:  %lf\n",(double)((double)(endarrow-startarrow)/(double)(countarrow)));
    printf("\nNumber of Vertices for Cross-shaped Polygons: 12\n");
    printf("Number of Cross-shaped Polygons Drawn: %u\n",countcross);
    printf("Time taken to draw a cross-shaped Polygon:  %lf\n",(double)((double)(endcross-startcross)/(double)(countcross)));

    exit (0);                           // No errors.
} // main


/******************************************************************************
 * draw_a_line                                                                *
 *  Function: draws a line from (x1, y1) to (x2, y2) using the Bresenham      *
 *            algorithm and the mach64 engine.                                *
 *    Inputs: x1 - starting x coordinate in pixels                            *
 *            y1 - starting y coordinate in pixels                            *
 *            x2 - ending x coordinate in pixels                              *
 *            y2 - ending y coordinate in pixels                              *
 *   Outputs: NONE                                                            *
 *     Notes: The drawing of the last pixel in the line is determined         *
 *            by the current setting of the DST_CNTL register (LAST_PEL       *
 *            bit).                                                           *
 *            24 bpp uses a special routine.                                  *
 ******************************************************************************/

void draw_a_line (int x1, int y1, int x2, int y2)
{
    int dx, dy;
    int small, large;
    int x_dir, y_dir, y_major;
    unsigned long err, inc, dec, temp;

    // Call specific routine if mode is in 24 bpp.
    if (MODE_INFO.bpp == 24)
    {
        draw_a_line24 (x1, y1, x2, y2);
        return;
    } // if

    // Determine x & y deltas and x & y direction bits.
    if (x1 < x2)
    {
        dx = x2 - x1;
        x_dir = 1;
    }
    else
    {
        dx = x1 - x2;
        x_dir = 0;
    } // if

    if (y1 < y2)
    {
        dy = y2 - y1;
        y_dir = 2;
    }
    else
    {
        dy = y1 - y2;
        y_dir = 0;
    } // if

    // Determine x & y min and max values; also determine y major bit.

    if (dx < dy)
    {
        small = dx;
        large = dy;
        y_major = 4;
    }
    else
    {
        small = dy;
        large = dx;
        y_major = 0;
    } // if

    // Calculate Bresenham parameters and draw line.
    err = (unsigned long) ((2 * small) - large);
    inc = (unsigned long) (2 * small);
    dec = 0x3FFFF - ((unsigned long) (2 * (large - small)));

    // Wait for idle before reading GUI registers.
    wait_for_idle ();

    // Save used registers.
    temp = regr (DST_CNTL);

    // Draw Bresenham line.
    regw (DST_X, (unsigned long) x1);
    regw (DST_Y, (unsigned long) y1);

    // Allow setting of last pel bit and polygon outline bit for line drawing.
    regw (DST_CNTL, (temp & 0x60) | (unsigned long) (y_major | y_dir | x_dir));
    regw (DST_BRES_ERR, err);
    regw (DST_BRES_INC, inc);
    regw (DST_BRES_DEC, dec);
    regw (DST_BRES_LNTH, (unsigned long) (large + 1));

    // Restore.
    regw (DST_CNTL, temp);

    return;

} // draw_a_line


/******************************************************************************
 * draw_a_line24                                                              *
 *  Function: draws a line from (x1, y1) to (x2, y2) using the Bresenham      *
 *            algorithm and the mach64 engine for 24bpp modes.                *
 *    Inputs: x1 - starting x coordinate in pixels                            *
 *            y1 - starting y coordinate in pixels                            *
 *            x2 - ending x coordinate in pixels                              *
 *            y2 - ending y coordinate in pixels                              *
 *   Outputs: NONE                                                            *
 *     Notes: Since the engine does not directly support 24 bpp modes,        *
 *            it is set to 8 bpp while the CRTC is set to 24 bpp display      *
 *            mode (RGB). For rectangle drawing, all X coordinates and        *
 *            widths must be converted to 8 bpp sizes. This is done by        *
 *            taking the 24 bpp value and multipling it by 3.                 *
 ******************************************************************************/

void draw_a_line24 (int x1, int y1, int x2, int y2)
{
    int x, y, xend, yend, dx, dy;
    int d, incr1, incr2, incr3;
    unsigned long rotation, temp1, temp2;

    // Save register.
    wait_for_idle ();
    temp1 = regr (DST_CNTL);
    temp2 = 0xA3;

    // Bresenham line routine.
    dx = abs (x2 - x1);
    dy = abs (y2 - y1);

    // Check slope.
    if (dy <= dx)
    {
        // Slope <= 1.

        if (x1 > x2)
        {
            x = x2;
            y = y2;
            xend = x1;
            dy = y1 - y2;
        }
        else
        {
            x = x1;
            y = y1;
            xend = x2;
            dy = y2 - y1;
        } // if

        d = (2 * dy) - dx;
        incr1 = 2 * dy;
        incr2 = 2 * (dy - dx);
        incr3 = 2 * (dy + dx);

        regw (DST_HEIGHT, 1);
        regw (DST_Y, y);

        do
        {
            wait_for_fifo (4);
            rotation = (unsigned long) (((x*3)/4)%6);
            regw (DST_CNTL, temp2 | (rotation << 8));
            regw (DST_X, x * 3);
            regw (DST_WIDTH, 3);

            x++;

            if (d >= 0)
            {
                if (dy <= 0)
                {
                    d = d + incr1;
                }
                else
                {
                    y++;
                    regw (DST_Y, y);
                    d = d + incr2;
                } // if
            }
            else
            {
                if (dy >= 0)
                {
                    d = d + incr1;
                }
                else
                {
                    y--;
                    regw (DST_Y, y);
                    d = d + incr3;
                } // if
            } // if
        } while (x <= xend);
    }
    else
    {
        // Slope > 1.

        if (y1 > y2)
        {
            y = y2;
            x = x2;
            yend = y1;
            dx = x1 - x2;
        }
        else
        {
            y = y1;
            x = x1;
            yend = y2;
            dx = x2 - x1;
        } // if

        d = (2 * dx) - dy;
        incr1 = 2 * dx;
        incr2 = 2 * (dx - dy);
        incr3 = 2 * (dx + dy);

        regw (DST_HEIGHT, 1);

        do
        {
            wait_for_fifo (3);
            rotation = (unsigned long) (((x*3)/4)%6);
            regw (DST_CNTL, temp2 | (rotation << 8));
            regw (DST_Y_X, ((unsigned long) (x * 3) << 16) | y);
            regw (DST_WIDTH, 3);

            y++;

            if (d >= 0)
            {
                if (dx <= 0)
                {
                    d = d + incr1;
                }
                else
                {
                    x++;
                    d = d + incr2;
                } // if
            }
            else
            {
                if (dx >= 0)
                {
                    d = d + incr1;
                }
                else
                {
                    x--;
                    d = d + incr3;
                } // if
            } // if
        } while (y <= yend);
    } // if

    // Restore register.

    wait_for_fifo (1);
    regw (DST_CNTL, temp1);

    return;

} // draw_a_line24

/******************************************************************************
 * draw_polygon                                                               *
 *  Function: draws a polygon on the screen by direct memory write to the     *
 *            linear aperture.  Special off screen buffer is created to       *
 *            determine fill regions.  This ensures that objects currently    *
 *            on screen will not interfere with the filling.  The outline     *
 *            of the polygon is first draw using the polygon structure of     *
 *            points.  A duplicate drawing is created in the buffer with      *
 *            1 bit representing a pixel.  The bits are toggled to            *
 *            appropriately indicate start and stop regions (horizontally)    *
 *            to fill.  The algoritm uses this buffer to determine what to    *
 *            fill.  Each horizontal pixel line is scanned from the buffer    *
 *            and appropriate horizontal lines are drawn on screen until      *
 *            the bottom of the shape is reached.                             *
 *    Inputs: pgon - structure containing list of point, and # of points      *
 *            xoff - x direction offset from the left in pixels               *
 *            yoff - y direction offset from the left in pixels               *
 *            colour values (0 - 16) representing first 16 vga colours        *
 *   Outputs: 0 - unsuccessful                                                *
 *            1 - successful                                                  *
 ******************************************************************************/

int draw_polygon (polygon *pgon, int xoff, int yoff, int colour)
{
    int count, row, col;
    int top, bottom ,left, right;
    int height, width;
    int flag;
    char *host;
    int this;
    int xold, yold;
    point *vertex;

    vertex = pgon->point_ptr;

    // Check to see if all points are on screen.
    for (count = 0; count < pgon->length; count++)
    {
        if ((vertex[count].x + xoff) < 0 ||
            (vertex[count].x + xoff) > (MODE_INFO.xres - 1) ||
            (vertex[count].y + yoff) < 0 ||
            (vertex[count].y + yoff) > (MODE_INFO.yres - 1))
        {
            return (0);
        } // if
    } // for

    // Find top, bottom, left and right.
    top = bottom = (vertex[0].y + yoff);
    left = right = (vertex[0].x + xoff);
    for (count = 1; count < pgon->length; count++)
    {
        if ((vertex[count].y + yoff) < top)
        {
            top = vertex[count].y + yoff;
        }
        else if ((vertex[count].y + yoff) > bottom)
        {
            bottom = vertex[count].y + yoff;
        } // if

        if ((vertex[count].x + xoff) < left)
        {
            left = vertex[count].x + xoff;
        }
        else if ((vertex[count].x + xoff) > right)
        {
            right = vertex[count].x + xoff;
        } // if
    } // for

    // Allocate space to create shape in host memory.
    height = bottom - top + 1;
    width = right - left + 1;
    host = (char *) calloc ((int) (1 + (height * ((float) width/8))),
                            sizeof (char));
    if (host == NULL) return (0);       // Error: no free memory.

    // Draw outline of polygon on screen and in host memory
    // vertices that are max and min have a value set to two points
    // this is automatically done when drawing the lines, but points that
    // are not maxs or mins need one point removed.
    // Further the draw line in memory routine draws y-independent lines
    // ie - only one point is drawn for each horizontal section of line.
    // This allows the fill switch to work properly.
    // Pure horizontal lines are not drawn in memory.  The fill ignores them.

    // Take care of first vertex.
    xoff=(MODE_INFO.xres-width)/2;
    yoff=(MODE_INFO.yres-height)/2;
    left=xoff+left;
    right=xoff+right;
    top=top+yoff;
    bottom=bottom+yoff;

    wait_for_fifo (2);
    regw (DP_FRGD_CLR, get_colour_code (colour));
    regw (DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
    draw_a_line ((vertex[0].x + xoff), (vertex[0].y + yoff),
               (vertex[1].x + xoff), (vertex[1].y + yoff));

    draw_memline (host, height, width,
                  (vertex[0].x - left + xoff), (vertex[0].y - top + yoff),
                  (vertex[1].x - left + xoff), (vertex[1].y - top + yoff));
    if (((vertex[0].y < vertex[1].y) &&
         (vertex[0].y > vertex[pgon->length-1].y)) ||
        ((vertex[0].y > vertex[1].y) &&
         (vertex[0].y < vertex[pgon->length-1].y)))
    {
        toggle_host (host,
                     ((unsigned long)(vertex[0].y + yoff - top))*width +
                      vertex[0].x + xoff - left);
    } // if

    // Take care of middle vertices.
    for (count = 1; count < pgon->length-1; count++)
    {

        wait_for_fifo (2);
        regw (DP_FRGD_CLR, get_colour_code (colour));
        regw (DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
        draw_a_line (vertex[count].x + xoff, vertex[count].y + yoff,
                   vertex[count+1].x + xoff, vertex[count+1].y + yoff);

        draw_memline (host, height, width,
                      vertex[count].x - left + xoff,
                      vertex[count].y - top + yoff,
                      vertex[count+1].x - left + xoff,
                      vertex[count+1].y - top + yoff);
        if (((vertex[count].y < vertex[count-1].y) &&
             (vertex[count].y > vertex[count+1].y)) ||
            ((vertex[count].y > vertex[count-1].y) &&
             (vertex[count].y < vertex[count+1].y)))
        {
            toggle_host (host,
                         ((unsigned long)(vertex[count].y + yoff - top))*width +
                         vertex[count].x + xoff - left);
        } // if
    } // for

    // Take care of last vertex.
    wait_for_fifo (2);
    regw (DP_FRGD_CLR, get_colour_code (colour));
    regw (DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
    draw_a_line (vertex[pgon->length - 1].x + xoff,
                 vertex[pgon->length - 1].y + yoff,
                 vertex[0].x + xoff, vertex[0].y + yoff);

    draw_memline (host, height, width,
                  vertex[pgon->length - 1].x - left + xoff,
                  vertex[pgon->length - 1].y - top + yoff,
                  vertex[0].x - left + xoff, vertex[0].y - top + yoff);
    if (((vertex[pgon->length-1].y < vertex[0].y) &&
         (vertex[pgon->length-1].y > vertex[pgon->length-2].y)) ||
        ((vertex[pgon->length-1].y > vertex[0].y) &&
         (vertex[pgon->length-1].y < vertex[pgon->length-2].y)))
    {
        toggle_host (host,
                     ((unsigned long)(vertex[pgon->length-1].y + yoff - top)) * width +
                     vertex[pgon->length-1].x + xoff - left);
    } // if

    // height = 0. Avoid infinite loop.
    if (bottom == top)
    {
        free (host);
        return (1);
    }

    // Scan each line and fill where appropriate.  The decision is made by
    // using the Host memory but the actual filling is only done on screen.

    for (row = top; row <= bottom; row ++)
    {
        flag = OFF;

        // Take care of the case where we start filling at column 0.

        if (read_host (host, (((unsigned long) (row - top))*width)))
        {
            flag = ON;
            xold = left;
            yold = row;
        } // if

        // Traverse across each row.

        for (col = left + 1; col <= right; col++)
        {
            this = read_host (host, ((unsigned long) (row - top))*width +
                                    col - left);


            if (flag == OFF)
            {
                // Filling is off.

                if (this)
                {
                    flag = ON;          // Indicate we are in fill section.
                    xold = col;
                    yold = row;
                } // if
            }
            else if (flag == ON)
            {
                // Filling is on.

                if (this)
                {
                    flag = OFF;         // Turn fill off when end is reached.
                    wait_for_fifo (2);
                    regw (DP_FRGD_CLR, get_colour_code (colour));
                    regw (DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
                    draw_a_line(xold,yold,col,yold);
                } // if
            } // if
        }
    } // for
    free (host);

    return (1);

} // draw_polygon


/******************************************************************************
 * read_host                                                                  *
 *  Function: Used with draw_polygon.  It reads the bit corresponding to      *
 *            the pixel on the screen at position (x,y).  value is 0 or 1     *
 *    Inputs: *host -  pointer to buffer of polygon                           *
 *            position - location of bit to read = y * pitch + x              *
 *   Outputs: value - bit value                                               *
 ******************************************************************************/

int read_host (char *host, unsigned long position)
{
    unsigned long byte_num;
    int bit_num;
    char value;
    char mask;

    byte_num = position / 8;
    bit_num = position % 8;
    value = host[byte_num];             // Read byte containing bit info.
    if (!value) return (0);
    {
        mask = 0;                           // Initialize mask.
    }

    mask = (1 << bit_num);              // Set up mask.
    value = mask & value;               // Get bit in question.

    return (value);

} // read_host


/******************************************************************************
 * toggle_host                                                                *
 *  Function: read, modify, write of bit corresponding to on screen pixel     *
 *            The bit is toggled.                                             *
 *    Inputs: *host - pointer to buffer of polygon                            *
 *            position - location of bit to read = y * pitch + x              *
 *   Outputs: value of 1 alway returned                                       *
 ******************************************************************************/

int toggle_host (char *host, unsigned long position)
{
    unsigned long byte_num;
    int bit_num;
    char value;
    char mask;

    byte_num = position / 8;
    bit_num = position % 8;
    value = host[byte_num];             // Read byte containing bit info.
    mask = 0;                           // Initialize mask.
    mask = (1 << bit_num);              // Set up mask.
    if (mask & value)                   // Bit is on.
    {
        mask = ~mask;                   // 1's complement.
        value = value & mask;           // Toggle required bit to 0.
    }
    else                                // Bit is off.
    {
        value = value | mask;           // Toggle required bit to 1.
    } // if
    host[byte_num] = value;             // Write byte.

    return (1);

} // toggle_host


/******************************************************************************
 * draw_mem_line                                                              *
 *  Function: used with draw_polygon.  line is drawn in a host buffer         *
 *            corresponding to an on screen image.  Lines are drawn as        *
 *            y-independant lines for fill algoritm reasons.                  *
 *    Inputs: *host - pointer to buffer of polygon                            *
 *            height of buffer                                                *
 *            width of buffer                                                 *
 *            x0 1st coordinate in pixels (0 = left, xres = right)            *
 *            y0 1st coordinate in pixels (0 = top, yres = bot)               *
 *            x1 2nd coordinate in pixels (0 = left, xres = right)            *
 *            y1 2nd coordinate in pixels (0 = top, yres = bot)               *
 *   Outputs: 1 is returned upon completion                                   *
 ******************************************************************************/

int draw_memline (char *host, int height, int width,
                  int x0, int y0, int x1, int y1)
{
    int t, dist;
    int xerr = 0, yerr = 0, xdel = 0, ydel = 0;
    int xinc, yinc;

    // Check to make sure that everything fits on screen.
    if ((x0 < 0) || (x0 >= width) || (y0 < 0) || (y0 >= height))
    {
        return (0);
    } // if
    if ((x1 < 0) || (x1 >= width) || (y1 < 0) || (y1 >= height))
    {
        return (0);
    } // if

    // Compute distances.

    xdel = x1 - x0;
    ydel = y1 - y0;

    // Compute direction.

    if (xdel > 0)
    {
        xinc = 1;
    }
    else if (xdel == 0)
    {
        xinc = 0;
    }
    else
    {
        xinc = -1;
    } // if
    if (ydel > 0)
    {
        yinc = 1;
    }
    else if (ydel == 0)
    {
        yinc = 0;
    }
    else
    {
        yinc = -1;
    } // if

    // Determine greater distance.

    xdel = abs (xdel);
    ydel = abs (ydel);
    if (xdel > ydel)
    {
        dist = xdel;
    }
    else
    {
        dist = ydel;
    } // if

    // Draw line if not horizontal - Horizontal lines are ignored.

    if (y0 == y1)
    {
        toggle_host (host, ((unsigned long)y0) * width + x0);
    }
    else
    {
        // Draw first point.

        toggle_host (host, ((unsigned long)y0) * width + x0);
        for (t = 1; t <= dist + 1; t++)
        {
            xerr += xdel;
            yerr += ydel;
            if (xerr > dist)
            {
                xerr -= dist;
                x0 += xinc;
            } // if

            // Make sure lines are y-independent
            if (yerr > dist)
            {
                yerr -= dist;
                y0 += yinc;
                toggle_host (host, ((unsigned long) y0) * width + x0);
            } // if
        } // for
    } // if

    return (1);

} // draw_memline


/******************************************************************************
 *  testa                                                                     *
 *  Function: test draws arrow at the centre of screen                        *
 *    Inputs: None                                                            *
 *   Outputs: 0 - if unsuccessful                                             *
 *            1 - if successful                                               *
 ******************************************************************************/
int testa (int a)
{
    point pts[20];
    polygon poly;
    float f1;
    int n1, n2;

    //  Initialize counter.
    countarrow=0;

    //  Commence the timing process.
    startarrow=*((unsigned int *) (DOS_TICK_ADDRESS));

    while (!kbhit ())
    {
        // Set up random numbers for # points, and colour.

        f1 = rand () / 32768.0;
        n1 = (int) (NUM_COLOURS * f1);

        n2= a;

        // Arrow-shaped polygon pointing at north-west.
        if (n2==1)
        {
            pts[0].x=0;
            pts[0].y=0;
            pts[1].x=60;
            pts[1].y=0;
            pts[2].x=45;
            pts[2].y=15;
            pts[3].x=90;
            pts[3].y=60;
            pts[4].x=60;
            pts[4].y=90;
            pts[5].x=15;
            pts[5].y=45;
            pts[6].x=0;
            pts[6].y=60;
        }

        // Arrow-shaped polygon pointing at south-west.
        else if (n2==2)
        {
            pts[0].x=0;
            pts[0].y=90;
            pts[1].x=0;
            pts[1].y=30;
            pts[2].x=15;
            pts[2].y=45;
            pts[3].x=60;
            pts[3].y=0;
            pts[4].x=90;
            pts[4].y=30;
            pts[5].x=45;
            pts[5].y=75;
            pts[6].x=60;
            pts[6].y=90;
        }

        // Arrow-shaped polygon pointing at south-east.
        else if (n2==3)
        {
            pts[0].x=90;
            pts[0].y=90;
            pts[1].x=30;
            pts[1].y=90;
            pts[2].x=45;
            pts[2].y=75;
            pts[3].x=0;
            pts[3].y=30;
            pts[4].x=30;
            pts[4].y=0;
            pts[5].x=75;
            pts[5].y=45;
            pts[6].x=90;
            pts[6].y=30;
        }

        // Arrow-shaped polygon pointing at north-east.
        else
        {
            pts[0].x=90;
            pts[0].y=0;
            pts[1].x=90;
            pts[1].y=60;
            pts[2].x=75;
            pts[2].y=45;
            pts[3].x=30;
            pts[3].y=90;
            pts[4].x=0;
            pts[4].y=60;
            pts[5].x=45;
            pts[5].y=15;
            pts[6].x=30;
            pts[6].y=0;
        }

        poly.length = 7;

        poly.point_ptr = pts;

        // Draw polygon.

        if (!draw_polygon (&poly, 0, 0, n1))
        {
            return (0);
        } // if

        //  Increment the counter.
        countarrow++;

    } // while

    //  Terminate the timing process.
    endarrow=*((unsigned int *) (DOS_TICK_ADDRESS));

    return (1);

} // testa

/******************************************************************************
 *  testb                                                                     *
 *  Function: test draws v-shaped poylgon at the centre of screen             *
 *    Inputs: None                                                            *
 *   Outputs: 0 - if unsuccessful                                             *
 *            1 - if successful                                               *
 ******************************************************************************/
int testb (void)
{
    point pts[20];
    polygon poly;
    float f1;
    int n1, n2;

    //  Initialize counter.
    countv=0;

    //  Commence the timing process.
    startv=*((unsigned int *) (DOS_TICK_ADDRESS));

    while (!kbhit ())
    {
        // Set up random numbers for # points, and colour.

        f1 = rand () / 32768.0;
        n1 = (int) (NUM_COLOURS * f1);

        n2= (rand() % 4)+1;

        // Inverted v-shaped polygon.
        if (n2==1)
        {
            pts[0].x=60;
            pts[0].y=0;
            pts[1].x=120;
            pts[1].y=120;
            pts[2].x=60;
            pts[2].y=60;
            pts[3].x=0;
            pts[3].y=120;
        }

        // V-shaped polygon rotated 90 degrees anti-clockwise.
        else if (n2==2)
        {
            pts[0].x=60;
            pts[0].y=60;
            pts[1].x=120;
            pts[1].y=0;
            pts[2].x=60;
            pts[2].y=120;
            pts[3].x=0;
            pts[3].y=0;
        }

        // V-shaped polygon.
        else if (n2==3)
        {
            pts[0].x=120;
            pts[0].y=0;
            pts[1].x=60;
            pts[1].y=60;
            pts[2].x=120;
            pts[2].y=120;
            pts[3].x=0;
            pts[3].y=60;
        }

        // V-shaped polygon rotated 90 degrees clockwise.
        else
        {
            pts[0].x=0;
            pts[0].y=0;
            pts[1].x=120;
            pts[1].y=60;
            pts[2].x=0;
            pts[2].y=120;
            pts[3].x=60;
            pts[3].y=60;
        }

        poly.length = 4;

        poly.point_ptr = pts;

        // Draw polygon.

        if (!draw_polygon (&poly, 0, 0, n1))
        {
            return (0);
        } // if

        //  Increment the counter.
        countv++;
    } // while

        //  Terminate the timing process.
        endv=*((unsigned int *) (DOS_TICK_ADDRESS));

    return (1);

} // testb

/******************************************************************************
 *  testc                                                                     *
 *  Function: Cross at centre of screen                                       *
 *    Inputs: None                                                            *
 *   Outputs: 0 - if unsuccessful                                             *
 *            1 - if successful                                               *
 ******************************************************************************/
int testc (void)
{
    point pts[20];
    polygon poly;
    float f1;
    int n1, n2;

    //  Initialize counter.
    countcross=0;

    //  Commence the timing process.
    startcross=*((unsigned int *) (DOS_TICK_ADDRESS));

    while (!kbhit ())
    {
        // Set up random numbers for # points, and colour.

        f1 = rand () / 32768.0;
        n1 = (int) (NUM_COLOURS * f1);

        pts[0].x=60;
        pts[0].y=0;
        pts[1].x=120;
        pts[1].y=0;
        pts[2].x=120;
        pts[2].y=60;
        pts[3].x=180;
        pts[3].y=60;
        pts[4].x=180;
        pts[4].y=120;
        pts[5].x=120;
        pts[5].y=120;
        pts[6].x=120;
        pts[6].y=180;
        pts[7].x=60;
        pts[7].y=180;
        pts[8].x=60;
        pts[8].y=120;
        pts[9].x=0;
        pts[9].y=120;
        pts[10].x=0;
        pts[10].y=60;
        pts[11].x=60;
        pts[11].y=60;
       
        poly.length = 12;

        poly.point_ptr = pts;

        // Draw polygon.

        if (!draw_polygon (&poly, 0, 0, n1))
        {
            return (0);
        } // if

        //  Increment the counter.
        countcross++;

    } // while

    //  Terminate the timing process.
    endcross=*((unsigned int *) (DOS_TICK_ADDRESS));

    return (1);

} // testc

