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