/* fill.c, a processor polygon filler */
/* Copyright (c) 1990 John Schultz, All Rights Reserved */

/* This is the C interface to the assembly code that does most of the   */
/* work. I haven't seen an algorithm of this type for filling polygons  */
/* elsewhere, so I'd like to think my implementation of this table fill */
/* algorithm is unique :-).The algorithm works by first finding out the */
/* orientation of the polygon, then filling the tables from miny to    */
/* maxy. This allows the table to be updated unconditionally, without */
/* having to read the current values from the tables, compare, then  */
/* write back to memory.                                            */
/* The polygons are an array of drawpoints, and you don't need to  */
/* close the polygons: a triangle will only have three points.    */

/* This code has been optimized for 320x200x4 bitmaps, which have */
/* been allocated linearly (One 32,000 byte allocation as opposed */
/* to four 8,000 byte allocations).                               */ 

/* To compile this code use: 
/*   lc -O -cuf -v fill.c                                         */
/*   asm scanconvert.a                                            */
/* Link to your own code as appropriate.                          */

/* I am using Lattice 5.04, and get a CXERR: 26, Line: 0, if the  */
/* optimizer is not used!                                         */

/* Look ma, no includes. */

typedef struct drawpoint {short dx,dy;} drawpoint;

#define MAXY 201                /* Bitmap max y + 1 */

short xmin[MAXY], xmax[MAXY]; /* Scanconverter tables */

short * xtable[] = {xmin,xmax}; /* For toggling between fill tables */

/* Prototypes */

extern void __asm drawline68k(register __a1 char * p, /* 1st Plane Ptr */
                              register __d0 short x,
                              register __d1 short y,
                              register __d2 short x2,
                              register __d3 short y2,
                              register __d4 short color);

extern void __asm fillline68k(register __d0 short x,
                              register __d1 short y,
                              register __d2 short x2,
                              register __d3 short y2,
                              register __a0 short * table);

extern void __asm scanconvpix(register __a0 char * p, /* 1st Plane Ptr */
                              register __a1 short * minx,
                              register __a2 short * maxx,
                              register __d0 short miny,
                              register __d1 short maxy,
                              register __d2 short color);

void drawpoly(drawpoint * dl, /* An array of drawpoints */
              char * p,      /* 1st Plane Ptr          */
              short cl,     /* Number of points       */
              short color);

/* Code */

void drawpoly(drawpoint * dl, /* An array of drawpoints */
              char * p,      /* 1st Plane Ptr          */
              short cl,     /* Number of points       */
              short color){
short miny,maxy;
short i,inext,index;
short tminy,tmaxy;
short j;
long orient=0;

/* Find out if polygon is clockwise or counterclockwise */

  for (i=0; i < cl; i++) {        /* Use the Newell method */
    if (i == (cl-1)) {
      j = 0;
    } else {
      j = i+1;
    }
    orient += (dl[i].dx - dl[j].dx)*(dl[i].dy + dl[j].dy);
  } /* for i */ 

  if (orient != 0) {    /* Check to see if we have a line or polygon */
    index = (orient < 0) ? 0 : 1;

/* Find miny,maxy */
    tminy = 199;
    tmaxy = 0;
    for (i=0; i < cl; i++) {
      if (dl[i].dy < tminy) {miny = i; tminy = dl[i].dy;}
      if (dl[i].dy > tmaxy) {maxy = i; tmaxy = dl[i].dy;}
    } /* for i */

/* Fill tables */
    i = miny; /* Start at top, fill to bottom, filling lines from top */
    do {     /* to bottom for efficient assembly implementation.     */
      inext = i + 1;
      if (inext >= cl) inext = 0; /* Wrap around */
      fillline68k(dl[i].dx,dl[i].dy,dl[inext].dx,dl[inext].dy,xtable[index]);
      if (inext == maxy) index ^= 1; /* Toggle min/max to keep lines    */
      i++;                          /* being filled from top to bottom */
      if (i >= cl) i = 0; /* Wrap around */
    } while (inext != miny); /* Come full circle, done */

/* Draw polygon */
   scanconvpix(p,xmin,xmax,tminy,tmaxy,color);

  } else { /* Draw a line */

/* This test really only works for triangles */
    if ((dl[0].dx == dl[1].dx) && (dl[0].dy == dl[1].dy))
      drawline68k(p,dl[0].dx,dl[0].dy,dl[1].dx,dl[1].dy,color);
    else
      drawline68k(p,dl[0].dx,dl[0].dy,dl[2].dx,dl[2].dy,color);

  } /* if orient */

} /* end drawpoly */

/* end fill.c */
