home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapter39 / l39-2.c < prev    next >
C/C++ Source or Header  |  1997-06-18  |  5KB  |  120 lines

  1. /* Scan converts an edge from (X1,Y1) to (X2,Y2), not including the
  2.    point at (X2,Y2). If SkipFirst == 1, the point at (X1,Y1) isn't
  3.    drawn; if SkipFirst == 0, it is. For each scan line, the pixel
  4.    closest to the scanned edge without being to the left of the
  5.    scanned edge is chosen. Uses an all-integer approach for speed and
  6.    precision
  7.  
  8.    Link with L21-1.C, L21-3.C, and L22-1.C in Compact model.
  9.    Tested with Borland C++ 4.02 by Jim Mischel 12/16/94.
  10. */
  11. #include <math.h>
  12. #include "polygon.h"
  13.  
  14. void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart,
  15.       int SkipFirst, struct HLine **EdgePointPtr)
  16. {
  17.    int Y, DeltaX, Height, Width, AdvanceAmt, ErrorTerm, i;
  18.    int ErrorTermAdvance, XMajorAdvanceAmt;
  19.    struct HLine *WorkingEdgePointPtr;
  20.  
  21.    WorkingEdgePointPtr = *EdgePointPtr; /* avoid double dereference */
  22.    AdvanceAmt = ((DeltaX = X2 - X1) > 0) ? 1 : -1;
  23.                             /* direction in which X moves (Y2 is
  24.                                always > Y1, so Y always counts up) */
  25.  
  26.    if ((Height = Y2 - Y1) <= 0)  /* Y length of the edge */
  27.       return;     /* guard against 0-length and horizontal edges */
  28.  
  29.    /* Figure out whether the edge is vertical, diagonal, X-major
  30.       (mostly horizontal), or Y-major (mostly vertical) and handle
  31.       appropriately */
  32.    if ((Width = abs(DeltaX)) == 0) {
  33.       /* The edge is vertical; special-case by just storing the same
  34.          X coordinate for every scan line */
  35.       /* Scan the edge for each scan line in turn */
  36.       for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
  37.          /* Store the X coordinate in the appropriate edge list */
  38.          if (SetXStart == 1)
  39.             WorkingEdgePointPtr->XStart = X1;
  40.          else
  41.             WorkingEdgePointPtr->XEnd = X1;
  42.       }
  43.    } else if (Width == Height) {
  44.       /* The edge is diagonal; special-case by advancing the X
  45.          coordinate 1 pixel for each scan line */
  46.       if (SkipFirst) /* skip the first point if so indicated */
  47.          X1 += AdvanceAmt; /* move 1 pixel to the left or right */
  48.       /* Scan the edge for each scan line in turn */
  49.       for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
  50.          /* Store the X coordinate in the appropriate edge list */
  51.          if (SetXStart == 1)
  52.             WorkingEdgePointPtr->XStart = X1;
  53.          else
  54.             WorkingEdgePointPtr->XEnd = X1;
  55.          X1 += AdvanceAmt; /* move 1 pixel to the left or right */
  56.       }
  57.    } else if (Height > Width) {
  58.       /* Edge is closer to vertical than horizontal (Y-major) */
  59.       if (DeltaX >= 0)
  60.          ErrorTerm = 0; /* initial error term going left->right */
  61.       else
  62.          ErrorTerm = -Height + 1;   /* going right->left */
  63.       if (SkipFirst) {   /* skip the first point if so indicated */
  64.          /* Determine whether it's time for the X coord to advance */
  65.          if ((ErrorTerm += Width) > 0) {
  66.             X1 += AdvanceAmt; /* move 1 pixel to the left or right */
  67.             ErrorTerm -= Height; /* advance ErrorTerm to next point */
  68.          }
  69.       }
  70.       /* Scan the edge for each scan line in turn */
  71.       for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
  72.          /* Store the X coordinate in the appropriate edge list */
  73.          if (SetXStart == 1)
  74.             WorkingEdgePointPtr->XStart = X1;
  75.          else
  76.             WorkingEdgePointPtr->XEnd = X1;
  77.          /* Determine whether it's time for the X coord to advance */
  78.          if ((ErrorTerm += Width) > 0) {
  79.             X1 += AdvanceAmt; /* move 1 pixel to the left or right */
  80.             ErrorTerm -= Height; /* advance ErrorTerm to correspond */
  81.          }
  82.       }
  83.    } else {
  84.       /* Edge is closer to horizontal than vertical (X-major) */
  85.       /* Minimum distance to advance X each time */
  86.       XMajorAdvanceAmt = (Width / Height) * AdvanceAmt;
  87.       /* Error term advance for deciding when to advance X 1 extra */
  88.       ErrorTermAdvance = Width % Height;
  89.       if (DeltaX >= 0)
  90.          ErrorTerm = 0; /* initial error term going left->right */
  91.       else
  92.          ErrorTerm = -Height + 1;   /* going right->left */
  93.       if (SkipFirst) {   /* skip the first point if so indicated */
  94.          X1 += XMajorAdvanceAmt;    /* move X minimum distance */
  95.          /* Determine whether it's time for X to advance one extra */
  96.          if ((ErrorTerm += ErrorTermAdvance) > 0) {
  97.             X1 += AdvanceAmt;       /* move X one more */
  98.             ErrorTerm -= Height; /* advance ErrorTerm to correspond */
  99.          }
  100.       }
  101.       /* Scan the edge for each scan line in turn */
  102.       for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) {
  103.          /* Store the X coordinate in the appropriate edge list */
  104.          if (SetXStart == 1)
  105.             WorkingEdgePointPtr->XStart = X1;
  106.          else
  107.             WorkingEdgePointPtr->XEnd = X1;
  108.          X1 += XMajorAdvanceAmt;    /* move X minimum distance */
  109.          /* Determine whether it's time for X to advance one extra */
  110.          if ((ErrorTerm += ErrorTermAdvance) > 0) {
  111.             X1 += AdvanceAmt;       /* move X one more */
  112.             ErrorTerm -= Height; /* advance ErrorTerm to correspond */
  113.          }
  114.       }
  115.    }
  116.  
  117.    *EdgePointPtr = WorkingEdgePointPtr;   /* advance caller's ptr */
  118. }
  119.  
  120.