home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 505a.lha / GrapicsGems / PolyScan / poly_scan.c < prev    next >
C/C++ Source or Header  |  1991-05-01  |  5KB  |  174 lines

  1. /*
  2.  * Generic Convex Polygon Scan Conversion and Clipping
  3.  * by Paul Heckbert
  4.  * from "Graphics Gems", Academic Press, 1990
  5.  */
  6.  
  7. /*
  8.  * poly_scan.c: point-sampled scan conversion of convex polygons
  9.  *
  10.  * Paul Heckbert    1985, Dec 1989
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <math.h>
  15. #include "poly.h"
  16.  
  17. /*
  18.  * poly_scan: Scan convert a polygon, calling pixelproc at each pixel with an
  19.  * interpolated Poly_vert structure.  Polygon can be clockwise or ccw.
  20.  * Polygon is clipped in 2-D to win, the screen space window.
  21.  *
  22.  * Scan conversion is done on the basis of Poly_vert fields sx and sy.
  23.  * These two must always be interpolated, and only they have special meaning
  24.  * to this code; any other fields are blindly interpolated regardless of
  25.  * their semantics.
  26.  *
  27.  * The pixelproc subroutine takes the arguments:
  28.  *
  29.  *    pixelproc(x, y, point)
  30.  *    int x, y;
  31.  *    Poly_vert *point;
  32.  *
  33.  * All the fields of point indicated by p->mask will be valid inside pixelproc
  34.  * except sx and sy.  If they were computed, they would have values
  35.  * sx=x+.5 and sy=y+.5, since sampling is done at pixel centers.
  36.  */
  37.  
  38. void poly_scan(p, win, pixelproc)
  39. register Poly *p;        /* polygon */
  40. Window *win;            /* 2-D screen space clipping window */
  41. void (*pixelproc)();        /* procedure called at each pixel */
  42. {
  43.     register int i, li, ri, y, ly, ry, top, rem, mask;
  44.     double ymin;
  45.     Poly_vert l, r, dl, dr;
  46.  
  47.     if (p->n>POLY_NMAX) {
  48.     fprintf(stderr, "poly_scan: too many vertices: %d\n", p->n);
  49.     return;
  50.     }
  51.  
  52.     ymin = HUGE;
  53.     for (i=0; i<p->n; i++)        /* find top vertex (y points down) */
  54.     if (p->vert[i].sy < ymin) {
  55.         ymin = p->vert[i].sy;
  56.         top = i;
  57.     }
  58.  
  59.     li = ri = top;            /* left and right vertex indices */
  60.     rem = p->n;                /* number of vertices remaining */
  61.     y = ceil(ymin-.5);            /* current scan line */
  62.     ly = ry = y-1;            /* lower end of left & right edges */
  63.     mask = p->mask & ~POLY_MASK(sy);    /* stop interpolating screen y */
  64.  
  65.     while (rem>0) {    /* scan in y, activating new edges on left & right */
  66.             /* as scan line passes over new vertices */
  67.  
  68.     while (ly<=y && rem>0) {    /* advance left edge? */
  69.         rem--;
  70.         i = li-1;            /* step ccw down left side */
  71.         if (i<0) i = p->n-1;
  72.         incrementalize_y(&p->vert[li], &p->vert[i], &l, &dl, y, mask);
  73.         ly = floor(p->vert[i].sy+.5);
  74.         li = i;
  75.     }
  76.     while (ry<=y && rem>0) {    /* advance right edge? */
  77.         rem--;
  78.         i = ri+1;            /* step cw down right edge */
  79.         if (i>=p->n) i = 0;
  80.         incrementalize_y(&p->vert[ri], &p->vert[i], &r, &dr, y, mask);
  81.         ry = floor(p->vert[i].sy+.5);
  82.         ri = i;
  83.     }
  84.  
  85.     while (y<ly && y<ry) {        /* do scanlines till end of l or r edge */
  86.         if (y>=win->y0 && y<=win->y1)
  87.         if (l.sx<=r.sx) scanline(y, &l, &r, win, pixelproc, mask);
  88.         else        scanline(y, &r, &l, win, pixelproc, mask);
  89.         y++;
  90.         increment(&l, &dl, mask);
  91.         increment(&r, &dr, mask);
  92.     }
  93.     }
  94. }
  95.  
  96. /* scanline: output scanline by sampling polygon at Y=y+.5 */
  97.  
  98. static scanline(y, l, r, win, pixelproc, mask)
  99. int y, mask;
  100. Poly_vert *l, *r;
  101. Window *win;
  102. void (*pixelproc)();
  103. {
  104.     int x, lx, rx;
  105.     Poly_vert p, dp;
  106.  
  107.     mask &= ~POLY_MASK(sx);        /* stop interpolating screen x */
  108.     lx = ceil(l->sx-.5);
  109.     if (lx<win->x0) lx = win->x0;
  110.     rx = floor(r->sx-.5);
  111.     if (rx>win->x1) rx = win->x1;
  112.     if (lx>rx) return;
  113.     incrementalize_x(l, r, &p, &dp, lx, mask);
  114.     for (x=lx; x<=rx; x++) {        /* scan in x, generating pixels */
  115.     (*pixelproc)(x, y, &p);
  116.     increment(&p, &dp, mask);
  117.     }
  118. }
  119.  
  120. /*
  121.  * incrementalize_y: put intersection of line Y=y+.5 with edge between points
  122.  * p1 and p2 in p, put change with respect to y in dp
  123.  */
  124.  
  125. static incrementalize_y(p1, p2, p, dp, y, mask)
  126. register double *p1, *p2, *p, *dp;
  127. register int mask;
  128. int y;
  129. {
  130.     double dy, frac;
  131.  
  132.     dy = ((Poly_vert *)p2)->sy - ((Poly_vert *)p1)->sy;
  133.     if (dy==0.) dy = 1.;
  134.     frac = y+.5 - ((Poly_vert *)p1)->sy;
  135.  
  136.     for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
  137.     if (mask&1) {
  138.         *dp = (*p2-*p1)/dy;
  139.         *p = *p1+*dp*frac;
  140.     }
  141. }
  142.  
  143. /*
  144.  * incrementalize_x: put intersection of line X=x+.5 with edge between points
  145.  * p1 and p2 in p, put change with respect to x in dp
  146.  */
  147.  
  148. static incrementalize_x(p1, p2, p, dp, x, mask)
  149. register double *p1, *p2, *p, *dp;
  150. register int mask;
  151. int x;
  152. {
  153.     double dx, frac;
  154.  
  155.     dx = ((Poly_vert *)p2)->sx - ((Poly_vert *)p1)->sx;
  156.     if (dx==0.) dx = 1.;
  157.     frac = x+.5 - ((Poly_vert *)p1)->sx;
  158.  
  159.     for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
  160.     if (mask&1) {
  161.         *dp = (*p2-*p1)/dx;
  162.         *p = *p1+*dp*frac;
  163.     }
  164. }
  165.  
  166. static increment(p, dp, mask)
  167. register double *p, *dp;
  168. register int mask;
  169. {
  170.     for (; mask!=0; mask>>=1, p++, dp++)
  171.     if (mask&1)
  172.         *p += *dp;
  173. }
  174.