home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / ppm / libppm5.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  17KB  |  697 lines

  1. /* libppm5.c - ppm utility library part 5
  2. **
  3. ** This library module contains the ppmdraw routines.
  4. **
  5. ** Copyright (C) 1989, 1991 by Jef Poskanzer.
  6. **
  7. ** Permission to use, copy, modify, and distribute this software and its
  8. ** documentation for any purpose and without fee is hereby granted, provided
  9. ** that the above copyright notice appear in all copies and that both that
  10. ** copyright notice and this permission notice appear in supporting
  11. ** documentation.  This software is provided "as is" without express or
  12. ** implied warranty.
  13. */
  14.  
  15. #include "ppm.h"
  16. #include "ppmdraw.h"
  17.  
  18. #define DDA_SCALE 8192
  19.  
  20. #if __STDC__
  21. void
  22. ppmd_point_drawproc( pixel** pixels, int cols, int rows, pixval maxval, int x, int y, char* clientdata )
  23. #else /*__STDC__*/
  24. void
  25. ppmd_point_drawproc( pixels, cols, rows, maxval, x, y, clientdata )
  26.     pixel** pixels;
  27.     int cols, rows, x, y;
  28.     pixval maxval;
  29.     char* clientdata;
  30. #endif /*__STDC__*/
  31.     {
  32.     if ( x >= 0 && x < cols && y >= 0 && y < rows )
  33.     pixels[y][x] = *( (pixel*) clientdata );
  34.     }
  35.  
  36.  
  37. /* Simple fill routine. */
  38.  
  39. #if __STDC__
  40. void
  41. ppmd_filledrectangle( pixel** pixels, int cols, int rows, pixval maxval, int x, int y, int width, int height, void (*drawprocP)(pixel**, int, int, pixval, int, int, char*), char* clientdata )
  42. #else /*__STDC__*/
  43. void
  44. ppmd_filledrectangle( pixels, cols, rows, maxval, x, y, width, height, drawprocP, clientdata )
  45.     pixel** pixels;
  46.     int cols, rows, x, y, width, height;
  47.     pixval maxval;
  48.     void (*drawprocP)();
  49.     char* clientdata;
  50. #endif /*__STDC__*/
  51.     {
  52.     register int cx, cy, cwidth, cheight, col, row;
  53.  
  54.     /* Clip. */
  55.     cx = x;
  56.     cy = y;
  57.     cwidth = width;
  58.     cheight = height;
  59.     if ( cx < 0 )
  60.     {
  61.     cx = 0;
  62.     cwidth += x;
  63.     }
  64.     if ( cy < 0 )
  65.     {
  66.     cy = 0;
  67.     cheight += y;
  68.     }
  69.     if ( cx + cwidth > cols )
  70.     cwidth = cols - cx;
  71.     if ( cy + cheight > rows )
  72.     cheight = rows - cy;
  73.  
  74.     /* Draw. */
  75.     for ( row = cy; row < cy + cheight; ++row )
  76.     for ( col = cx; col < cx + cwidth; ++col )
  77.         if ( drawprocP == PPMD_NULLDRAWPROC )
  78.         pixels[row][col] = *( (pixel*) clientdata );
  79.         else
  80.         (*drawprocP)(
  81.             pixels, cols, rows, maxval, col, row, clientdata );
  82.     }
  83.  
  84.  
  85. /* Outline drawing stuff. */
  86.  
  87. static int ppmd_linetype = PPMD_LINETYPE_NORMAL;
  88.  
  89. int
  90. ppmd_setlinetype( type )
  91.     int type;
  92.     {
  93.     int old;
  94.  
  95.     old = ppmd_linetype;
  96.     ppmd_linetype = type;
  97.     return old;
  98.     }
  99.  
  100. static int ppmd_lineclip = 1;
  101.  
  102. int
  103. ppmd_setlineclip( clip )
  104.     int clip;
  105.     {
  106.     int old;
  107.  
  108.     old = ppmd_lineclip;
  109.     ppmd_lineclip = clip;
  110.     return old;
  111.     }
  112.  
  113. #if __STDC__
  114. void
  115. ppmd_line( pixel** pixels, int cols, int rows, pixval maxval, int x0, int y0, int x1, int y1, void (*drawprocP)(pixel**, int, int, pixval, int, int, char*), char* clientdata )
  116. #else /*__STDC__*/
  117. void
  118. ppmd_line( pixels, cols, rows, maxval, x0, y0, x1, y1, drawprocP, clientdata )
  119.     pixel** pixels;
  120.     int cols, rows, x0, y0, x1, y1;
  121.     pixval maxval;
  122.     void (*drawprocP)();
  123.     char* clientdata;
  124. #endif /*__STDC__*/
  125.     {
  126.     register int cx0, cy0, cx1, cy1;
  127.  
  128.     /* Special case zero-length lines. */
  129.     if ( x0 == x1 && y0 == y1 )
  130.     {
  131.     if ( ( ! ppmd_lineclip ) ||
  132.          ( x0 >= 0 && x0 < cols && y0 >= 0 && y0 < rows ) )
  133.         if ( drawprocP == PPMD_NULLDRAWPROC )
  134.         ppmd_point_drawproc(
  135.             pixels, cols, rows, maxval, x0, y0, clientdata );
  136.         else
  137.         (*drawprocP)( pixels, cols, rows, maxval, x0, y0, clientdata );
  138.     return;
  139.     }
  140.  
  141.     /* Clip. */
  142.     cx0 = x0;
  143.     cy0 = y0;
  144.     cx1 = x1;
  145.     cy1 = y1;
  146.     if ( ppmd_lineclip )
  147.     {
  148.     if ( cx0 < 0 )
  149.         {
  150.         if ( cx1 < 0 ) return;
  151.         cy0 = cy0 + ( cy1 - cy0 ) * ( -cx0 ) / ( cx1 - cx0 );
  152.         cx0 = 0;
  153.         }
  154.     else if ( cx0 >= cols )
  155.         {
  156.         if ( cx1 >= cols ) return;
  157.         cy0 = cy0 + ( cy1 - cy0 ) * ( cols - 1 - cx0 ) / ( cx1 - cx0 );
  158.         cx0 = cols - 1;
  159.         }
  160.     if ( cy0 < 0 )
  161.         {
  162.         if ( cy1 < 0 ) return;
  163.         cx0 = cx0 + ( cx1 - cx0 ) * ( -cy0 ) / ( cy1 - cy0 );
  164.         cy0 = 0;
  165.         }
  166.     else if ( cy0 >= rows )
  167.         {
  168.         if ( cy1 >= rows ) return;
  169.         cx0 = cx0 + ( cx1 - cx0 ) * ( rows - 1 - cy0 ) / ( cy1 - cy0 );
  170.         cy0 = rows - 1;
  171.         }
  172.     if ( cx1 < 0 )
  173.         {
  174.         cy1 = cy1 + ( cy0 - cy1 ) * ( -cx1 ) / ( cx0 - cx1 );
  175.         cx1 = 0;
  176.         }
  177.     else if ( cx1 >= cols )
  178.         {
  179.         cy1 = cy1 + ( cy0 - cy1 ) * ( cols - 1 - cx1 ) / ( cx0 - cx1 );
  180.         cx1 = cols - 1;
  181.         }
  182.     if ( cy1 < 0 )
  183.         {
  184.         cx1 = cx1 + ( cx0 - cx1 ) * ( -cy1 ) / ( cy0 - cy1 );
  185.         cy1 = 0;
  186.         }
  187.     else if ( cy1 >= rows )
  188.         {
  189.         cx1 = cx1 + ( cx0 - cx1 ) * ( rows - 1 - cy1 ) / ( cy0 - cy1 );
  190.         cy1 = rows - 1;
  191.         }
  192.  
  193.     /* Check again for zero-length lines. */
  194.     if ( cx0 == cx1 && cy0 == cy1 )
  195.         {
  196.         if ( drawprocP == PPMD_NULLDRAWPROC )
  197.         ppmd_point_drawproc(
  198.             pixels, cols, rows, maxval, cx0, cy0, clientdata );
  199.         else
  200.         (*drawprocP)(
  201.             pixels, cols, rows, maxval, cx0, cy0, clientdata );
  202.         return;
  203.         }
  204.     }
  205.  
  206.     /* Draw, using a simple DDA. */
  207.     if ( abs( cx1 - cx0 ) > abs( cy1 - cy0 ) )
  208.     { /* Loop over X domain. */
  209.     register long dy, srow;
  210.     register int dx, col, row, prevrow;
  211.  
  212.     if ( cx1 > cx0 )
  213.         dx = 1;
  214.     else
  215.         dx = -1;
  216.     dy = ( cy1 - cy0 ) * DDA_SCALE / abs( cx1 - cx0 );
  217.     prevrow = row = cy0;
  218.     srow = row * DDA_SCALE + DDA_SCALE / 2;
  219.     col = cx0;
  220.     for ( ; ; )
  221.         {
  222.         if ( ppmd_linetype == PPMD_LINETYPE_NODIAGS && row != prevrow )
  223.         {
  224.         if ( drawprocP == PPMD_NULLDRAWPROC )
  225.             pixels[prevrow][col] = *( (pixel*) clientdata );
  226.         else
  227.             (*drawprocP)(
  228.                 pixels, cols, rows, maxval, col, prevrow, clientdata );
  229.         prevrow = row;
  230.         }
  231.         if ( drawprocP == PPMD_NULLDRAWPROC )
  232.         pixels[row][col] = *( (pixel*) clientdata );
  233.         else
  234.         (*drawprocP)(
  235.             pixels, cols, rows, maxval, col, row, clientdata );
  236.         if ( col == cx1 )
  237.         break;
  238.         srow += dy;
  239.         row = srow / DDA_SCALE;
  240.         col += dx;
  241.         }
  242.     }
  243.     else
  244.     { /* Loop over Y domain. */
  245.     register long dx, scol;
  246.     register int dy, col, row, prevcol;
  247.  
  248.     if ( cy1 > cy0 )
  249.         dy = 1;
  250.     else
  251.         dy = -1;
  252.     dx = ( cx1 - cx0 ) * DDA_SCALE / abs( cy1 - cy0 );
  253.     row = cy0;
  254.     prevcol = col = cx0;
  255.     scol = col * DDA_SCALE + DDA_SCALE / 2;
  256.     for ( ; ; )
  257.         {
  258.         if ( ppmd_linetype == PPMD_LINETYPE_NODIAGS && col != prevcol )
  259.         {
  260.         if ( drawprocP == PPMD_NULLDRAWPROC )
  261.             pixels[row][prevcol] = *( (pixel*) clientdata );
  262.         else
  263.             (*drawprocP)(
  264.             pixels, cols, rows, maxval, prevcol, row, clientdata );
  265.         prevcol = col;
  266.         }
  267.         if ( drawprocP == PPMD_NULLDRAWPROC )
  268.         pixels[row][col] = *( (pixel*) clientdata );
  269.         else
  270.         (*drawprocP)(
  271.             pixels, cols, rows, maxval, col, row, clientdata );
  272.         if ( row == cy1 )
  273.         break;
  274.         row += dy;
  275.         scol += dx;
  276.         col = scol / DDA_SCALE;
  277.         }
  278.     }
  279.     }
  280.  
  281. #define SPLINE_THRESH 3
  282. #if __STDC__
  283. void
  284. ppmd_spline3( pixel** pixels, int cols, int rows, pixval maxval, int x0, int y0, int x1, int y1, int x2, int y2, void (*drawprocP)(pixel**, int, int, pixval, int, int, char*), char* clientdata )
  285. #else /*__STDC__*/
  286. void
  287. ppmd_spline3( pixels, cols, rows, maxval, x0, y0, x1, y1, x2, y2, drawprocP, clientdata )
  288.     pixel** pixels;
  289.     int cols, rows, x0, y0, x1, y1, x2, y2;
  290.     pixval maxval;
  291.     void (*drawprocP)();
  292.     char* clientdata;
  293. #endif /*__STDC__*/
  294.     {
  295.     register int xa, ya, xb, yb, xc, yc, xp, yp;
  296.  
  297.     xa = ( x0 + x1 ) / 2;
  298.     ya = ( y0 + y1 ) / 2;
  299.     xc = ( x1 + x2 ) / 2;
  300.     yc = ( y1 + y2 ) / 2;
  301.     xb = ( xa + xc ) / 2;
  302.     yb = ( ya + yc ) / 2;
  303.  
  304.     xp = ( x0 + xb ) / 2;
  305.     yp = ( y0 + yb ) / 2;
  306.     if ( abs( xa - xp ) + abs( ya - yp ) > SPLINE_THRESH )
  307.     ppmd_spline3(
  308.         pixels, cols, rows, maxval, x0, y0, xa, ya, xb, yb, drawprocP,
  309.         clientdata );
  310.     else
  311.     ppmd_line(
  312.         pixels, cols, rows, maxval, x0, y0, xb, yb, drawprocP, clientdata );
  313.  
  314.     xp = ( x2 + xb ) / 2;
  315.     yp = ( y2 + yb ) / 2;
  316.     if ( abs( xc - xp ) + abs( yc - yp ) > SPLINE_THRESH )
  317.     ppmd_spline3(
  318.         pixels, cols, rows, maxval, xb, yb, xc, yc, x2, y2, drawprocP,
  319.         clientdata );
  320.     else
  321.     ppmd_line(
  322.         pixels, cols, rows, maxval, xb, yb, x2, y2, drawprocP, clientdata );
  323.     }
  324.  
  325. #if __STDC__
  326. void
  327. ppmd_polyspline( pixel** pixels, int cols, int rows, pixval maxval, int x0, int y0, int nc, int* xc, int* yc, int x1, int y1, void (*drawprocP)(pixel**, int, int, pixval, int, int, char*), char* clientdata )
  328. #else /*__STDC__*/
  329. void
  330. ppmd_polyspline( pixels, cols, rows, maxval, x0, y0, nc, xc, yc, x1, y1, drawprocP, clientdata )
  331.     pixel** pixels;
  332.     int cols, rows, x0, y0, nc, x1, y1;
  333.     int* xc;
  334.     int* yc;
  335.     pixval maxval;
  336.     void (*drawprocP)();
  337.     char* clientdata;
  338. #endif /*__STDC__*/
  339.     {
  340.     register int i, x, y, xn, yn;
  341.  
  342.     x = x0;
  343.     y = y0;
  344.     for ( i = 0; i < nc - 1; ++i )
  345.     {
  346.     xn = ( xc[i] + xc[i + 1] ) / 2;
  347.     yn = ( yc[i] + yc[i + 1] ) / 2;
  348.     ppmd_spline3(
  349.         pixels, cols, rows, maxval, x, y, xc[i], yc[i], xn, yn, drawprocP,
  350.         clientdata );
  351.     x = xn;
  352.     y = yn;
  353.     }
  354.     ppmd_spline3(
  355.     pixels, cols, rows, maxval, x, y, xc[nc - 1], yc[nc - 1], x1, y1,
  356.     drawprocP, clientdata );
  357.     }
  358.  
  359. #if __STDC__
  360. void
  361. ppmd_circle( pixel** pixels, int cols, int rows, pixval maxval, int cx, int cy, int radius, void (*drawprocP)(pixel**, int, int, pixval, int, int, char*), char* clientdata )
  362. #else /*__STDC__*/
  363. void
  364. ppmd_circle( pixels, cols, rows, maxval, cx, cy, radius, drawprocP, clientdata )
  365.     pixel** pixels;
  366.     int cols, rows, cx, cy, radius;
  367.     pixval maxval;
  368.     void (*drawprocP)();
  369.     char* clientdata;
  370. #endif /*__STDC__*/
  371.     {
  372.     register int x0, y0, x, y, prevx, prevy, nopointsyet;
  373.     register long sx, sy, e;
  374.  
  375.     x0 = x = radius;
  376.     y0 = y = 0;
  377.     sx = x * DDA_SCALE + DDA_SCALE / 2;
  378.     sy = y * DDA_SCALE + DDA_SCALE / 2;
  379.     e = DDA_SCALE / radius;
  380.     if ( drawprocP == PPMD_NULLDRAWPROC )
  381.     pixels[y + cy][x + cx] = *( (pixel*) clientdata );
  382.     else
  383.     (*drawprocP)( pixels, cols, rows, maxval, x + cx, y + cy, clientdata );
  384.     nopointsyet = 1;
  385.     do
  386.     {
  387.     prevx = x;
  388.     prevy = y;
  389.     sx += e * sy / DDA_SCALE;
  390.     sy -= e * sx / DDA_SCALE;
  391.     x = sx / DDA_SCALE;
  392.     y = sy / DDA_SCALE;
  393.     if ( x != prevx || y != prevy )
  394.         {
  395.         nopointsyet = 0;
  396.         if ( drawprocP == PPMD_NULLDRAWPROC )
  397.         pixels[y + cy][x + cx] = *( (pixel*) clientdata );
  398.         else
  399.         (*drawprocP)(
  400.             pixels, cols, rows, maxval, x + cx, y + cy, clientdata );
  401.         }
  402.     }
  403.     while ( nopointsyet || x != x0 || y != y0 );
  404.     }
  405.  
  406.  
  407. /* Arbitrary fill stuff. */
  408.  
  409. typedef struct
  410.     {
  411.     short x;
  412.     short y;
  413.     short edge;
  414.     } coord;
  415. typedef struct
  416.     {
  417.     int n;
  418.     int size;
  419.     int curedge;
  420.     int segstart;
  421.     int ydir;
  422.     int startydir;
  423.     coord* coords;
  424.     } fillobj;
  425.  
  426. #define SOME 1000
  427.  
  428. static int oldclip;
  429.  
  430. char*
  431. ppmd_fill_init( )
  432.     {
  433.     fillobj* fh;
  434.  
  435.     fh = (fillobj*) malloc( sizeof(fillobj) );
  436.     if ( fh == 0 )
  437.     pm_error( "out of memory allocating a fillhandle" );
  438.     fh->n = 0;
  439.     fh->coords = (coord*) malloc( SOME * sizeof(coord) );
  440.     if ( fh->coords == 0 )
  441.     pm_error( "out of memory allocating a fillhandle" );
  442.     fh->size = SOME;
  443.     fh->curedge = 0;
  444.  
  445.     /* Turn off line clipping. */
  446.     oldclip = ppmd_setlineclip( 0 );
  447.     
  448.     return (char*) fh;
  449.     }
  450.  
  451. #if __STDC__
  452. void
  453. ppmd_fill_drawproc( pixel** pixels, int cols, int rows, pixval maxval, int x, int y, char* clientdata )
  454. #else /*__STDC__*/
  455. void
  456. ppmd_fill_drawproc( pixels, cols, rows, maxval, x, y, clientdata )
  457.     pixel** pixels;
  458.     int cols, rows, x, y;
  459.     pixval maxval;
  460.     char* clientdata;
  461. #endif /*__STDC__*/
  462.     {
  463.     register fillobj* fh;
  464.     register coord* cp;
  465.     register coord* ocp;
  466.  
  467.     fh = (fillobj*) clientdata;
  468.  
  469.     if ( fh->n > 0 )
  470.     {
  471.     /* If these are the same coords we saved last time, don't bother. */
  472.     ocp = &(fh->coords[fh->n - 1]);
  473.     if ( x == ocp->x && y == ocp->y )
  474.         return;
  475.     }
  476.  
  477.     /* Ok, these are new; check if there's room for two more coords. */
  478.     if ( fh->n + 1 >= fh->size )
  479.     {
  480.     fh->size += SOME;
  481.     fh->coords = (coord*) realloc(
  482.         (char*) fh->coords, fh->size * sizeof(coord) );
  483.     if ( fh->coords == 0 )
  484.         pm_error( "out of memory enlarging a fillhandle" );
  485.     }
  486.  
  487.     /* Check for extremum and set the edge number. */
  488.     if ( fh->n == 0 )
  489.     { /* Start first segment. */
  490.     fh->segstart = fh->n;
  491.     fh->ydir = 0;
  492.     fh->startydir = 0;
  493.     }
  494.     else
  495.     {
  496.     register int dx, dy;
  497.  
  498.     dx = x - ocp->x;
  499.     dy = y - ocp->y;
  500.     if ( dx < -1 || dx > 1 || dy < -1 || dy > 1 )
  501.         { /* Segment break.  Close off old one. */
  502.         if ( fh->startydir != 0 && fh->ydir != 0 )
  503.         if ( fh->startydir == fh->ydir )
  504.             { /* Oops, first edge and last edge are the same.
  505.               ** Renumber the first edge in the old segment. */
  506.             register coord* fcp;
  507.             int oldedge;
  508.  
  509.             fcp = &(fh->coords[fh->segstart]);
  510.             oldedge = fcp->edge;
  511.             for ( ; fcp->edge == oldedge; ++fcp )
  512.             fcp->edge = ocp->edge;
  513.             }
  514.         /* And start new segment. */
  515.         ++(fh->curedge);
  516.         fh->segstart = fh->n;
  517.         fh->ydir = 0;
  518.         fh->startydir = 0;
  519.         }
  520.     else
  521.         { /* Segment continues. */
  522.         if ( dy != 0 )
  523.         {
  524.         if ( fh->ydir != 0 && fh->ydir != dy )
  525.             { /* Direction changed.  Insert a fake coord, old
  526.               ** position but new edge number. */
  527.             ++(fh->curedge);
  528.             cp = &(fh->coords[fh->n]);
  529.             cp->x = ocp->x;
  530.             cp->y = ocp->y;
  531.             cp->edge = fh->curedge;
  532.             ++(fh->n);
  533.             }
  534.         fh->ydir = dy;
  535.         if ( fh->startydir == 0 )
  536.             fh->startydir = dy;
  537.         }
  538.         }
  539.     }
  540.  
  541.     /* Save this coord. */
  542.     cp = &(fh->coords[fh->n]);
  543.     cp->x = x;
  544.     cp->y = y;
  545.     cp->edge = fh->curedge;
  546.     ++(fh->n);
  547.     }
  548.  
  549. static int yx_compare ARGS((coord* c1, coord* c2));
  550. static int
  551. yx_compare( c1, c2 )
  552.     coord* c1;
  553.     coord* c2;
  554.     {
  555.     if ( c1->y > c2->y )
  556.     return 1;
  557.     if ( c1->y < c2->y )
  558.     return -1;
  559.     if ( c1->x > c2->x )
  560.     return 1;
  561.     if ( c1->x < c2->x )
  562.     return -1;
  563.     return 0;
  564.     }
  565.  
  566. #if __STDC__
  567. void
  568. ppmd_fill( pixel** pixels, int cols, int rows, pixval maxval, char* fillhandle, void (*drawprocP)(pixel**, int, int, pixval, int, int, char*), char* clientdata )
  569. #else /*__STDC__*/
  570. void
  571. ppmd_fill( pixels, cols, rows, maxval, fillhandle, drawprocP, clientdata )
  572.     pixel** pixels;
  573.     int cols, rows;
  574.     pixval maxval;
  575.     char* fillhandle;
  576.     void (*drawprocP)();
  577.     char* clientdata;
  578. #endif /*__STDC__*/
  579.     {
  580.     register fillobj* fh;
  581.     int pedge, eq;
  582.     register int i, leftside, edge, lx, rx, py;
  583.     register coord* cp;
  584.  
  585.     fh = (fillobj*) fillhandle;
  586.  
  587.     /* Close off final segment. */
  588.     if ( fh->n > 0 && fh->startydir != 0 && fh->ydir != 0 )
  589.     if ( fh->startydir == fh->ydir )
  590.         { /* Oops, first edge and last edge are the same. */
  591.         register coord* fcp;
  592.         int lastedge, oldedge;
  593.  
  594.         lastedge = fh->coords[fh->n - 1].edge;
  595.         fcp = &(fh->coords[fh->segstart]);
  596.         oldedge = fcp->edge;
  597.         for ( ; fcp->edge == oldedge; ++fcp )
  598.         fcp->edge = lastedge;
  599.         }
  600.  
  601.     /* Restore clipping now. */
  602.     (void) ppmd_setlineclip( oldclip );
  603.  
  604.     /* Sort the coords by Y, secondarily by X. */
  605.     qsort( (char*) fh->coords, fh->n, sizeof(coord), yx_compare );
  606.  
  607.     /* Find equal coords with different edge numbers, and swap if necessary. */
  608.     edge = -1;
  609.     for ( i = 0; i < fh->n; ++i )
  610.     {
  611.     cp = &(fh->coords[i]);
  612.     if ( i > 1 && eq && cp->edge != edge && cp->edge == pedge )
  613.         { /* Swap .-1 and .-2. */
  614.         coord t;
  615.  
  616.         t = fh->coords[i-1];
  617.         fh->coords[i-1] = fh->coords[i-2];
  618.         fh->coords[i-2] = t;
  619.         }
  620.     if ( i > 0 )
  621.         {
  622.         if ( cp->x == lx && cp->y == py )
  623.         {
  624.         eq = 1;
  625.         if ( cp->edge != edge && cp->edge == pedge )
  626.             { /* Swap . and .-1. */
  627.             coord t;
  628.  
  629.             t = *cp;
  630.             *cp = fh->coords[i-1];
  631.             fh->coords[i-1] = t;
  632.             }
  633.         }
  634.         else
  635.         eq = 0;
  636.         }
  637.     lx = cp->x;
  638.     py = cp->y;
  639.     pedge = edge;
  640.     edge = cp->edge;
  641.     }
  642.  
  643.     /* Ok, now run through the coords filling spans. */
  644.     for ( i = 0; i < fh->n; ++i )
  645.     {
  646.     cp = &(fh->coords[i]);
  647.     if ( i == 0 )
  648.         {
  649.         lx = rx = cp->x;
  650.         py = cp->y;
  651.         edge = cp->edge;
  652.         leftside = 1;
  653.         }
  654.     else
  655.         {
  656.         if ( cp->y != py )
  657.         { /* Row changed.  Emit old span and start a new one. */
  658.         ppmd_filledrectangle(
  659.             pixels, cols, rows, maxval, lx, py, rx - lx + 1, 1,
  660.             drawprocP, clientdata);
  661.         lx = rx = cp->x;
  662.         py = cp->y;
  663.         edge = cp->edge;
  664.         leftside = 1;
  665.         }
  666.         else
  667.         {
  668.         if ( cp->edge == edge )
  669.             { /* Continuation of side. */
  670.             rx = cp->x;
  671.             }
  672.         else
  673.             { /* Edge changed.  Is it a span? */
  674.             if ( leftside )
  675.             {
  676.             rx = cp->x;
  677.             leftside = 0;
  678.             }
  679.             else
  680.             { /* Got a span to fill. */
  681.             ppmd_filledrectangle(
  682.                 pixels, cols, rows, maxval, lx, py, rx - lx + 1,
  683.                 1, drawprocP, clientdata);
  684.             lx = rx = cp->x;
  685.             leftside = 1;
  686.             }
  687.             edge = cp->edge;
  688.             }
  689.         }
  690.         }
  691.     }
  692.  
  693.     /* All done.  Free up the fillhandle and leave. */
  694.     free( fh->coords );
  695.     free( fh );
  696.     }
  697.