home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 309.lha / PBM_PLUS / ppm / libppm5.c < prev    next >
C/C++ Source or Header  |  1980-12-04  |  13KB  |  560 lines

  1. /* libppm5.c - ppm utility library part 5
  2. **
  3. ** This library module contains the ppmdraw routines.
  4. **
  5. ** Copyright (C) 1989 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 <stdio.h>
  16. #include "ppm.h"
  17. #include "ppmdraw.h"
  18.  
  19.  
  20. #define DDA_SCALE 8192
  21. #define abs(x) ((x) < 0 ? -(x) : (x))
  22. #define min(x,y) ((x) < (y) ? (x) : (y))
  23. #define max(x,y) ((x) > (y) ? (x) : (y))
  24.  
  25.  
  26. void
  27. ppmd_point_drawproc( pixels, cols, rows, maxval, x, y, clientdata )
  28. pixel **pixels;
  29. int cols, rows, x, y;
  30. pixval maxval;
  31. char *clientdata;
  32.     {
  33.     if ( x >= 0 && x < cols && y >= 0 && y < rows )
  34.     pixels[y][x] = *( (pixel *) clientdata );
  35.     }
  36.  
  37.  
  38. /* Simple fill routine. */
  39.  
  40. void
  41. ppmd_filledrectangle( pixels, cols, rows, maxval, x, y, width, height, drawprocP, clientdata)
  42. pixel **pixels;
  43. int cols, rows, x, y, width, height;
  44. pixval maxval;
  45. void (*drawprocP)();
  46. char *clientdata;
  47.     {
  48.     register cx, cy, cwidth, cheight, col, row;
  49.  
  50.     /* Clip. */
  51.     cx = x;
  52.     cy = y;
  53.     cwidth = width;
  54.     cheight = height;
  55.     if ( cx < 0 )
  56.     {
  57.     cx = 0;
  58.     cwidth += x;
  59.     }
  60.     if ( cy < 0 )
  61.     {
  62.     cy = 0;
  63.     cheight += y;
  64.     }
  65.     if ( cx + cwidth > cols )
  66.     cwidth = cols - cx;
  67.     if ( cy + cheight > rows )
  68.     cheight = rows - cy;
  69.  
  70.     /* Draw. */
  71.     for ( row = cy; row < cy + cheight; row++ )
  72.     for ( col = cx; col < cx + cwidth; col++ )
  73.         if ( drawprocP == PPMD_NULLDRAWPROC )
  74.         pixels[row][col] = *( (pixel *) clientdata );
  75.         else
  76.         (*drawprocP)(
  77.             pixels, cols, rows, maxval, col, row, clientdata );
  78.     }
  79.  
  80.  
  81. /* Outline drawing stuff. */
  82.  
  83. static int ppmd_linetype = PPMD_LINETYPE_NORMAL;
  84.  
  85. int
  86. ppmd_setlinetype( type )
  87. int type;
  88.     {
  89.     int old;
  90.  
  91.     old = ppmd_linetype;
  92.     ppmd_linetype = type;
  93.     return old;
  94.     }
  95.  
  96. static int ppmd_lineclip = 1;
  97.  
  98. int
  99. ppmd_setlineclip( clip )
  100. int clip;
  101.     {
  102.     int old;
  103.  
  104.     old = ppmd_lineclip;
  105.     ppmd_lineclip = clip;
  106.     return old;
  107.     }
  108.  
  109. void
  110. ppmd_line( pixels, cols, rows, maxval, x0, y0, x1, y1, drawprocP, clientdata )
  111. pixel **pixels;
  112. int cols, rows, x0, y0, x1, y1;
  113. pixval maxval;
  114. void (*drawprocP)();
  115. char *clientdata;
  116.     {
  117.     register int cx0, cy0, cx1, cy1;
  118.  
  119.     /* Special case zero-length lines. */
  120.     if ( x0 == x1 && y0 == y1 )
  121.     {
  122.     if ( drawprocP == PPMD_NULLDRAWPROC )
  123.         ppmd_point_drawproc(
  124.         pixels, cols, rows, maxval, x0, y0, clientdata );
  125.     else
  126.         (*drawprocP)( pixels, cols, rows, maxval, x0, y0, clientdata );
  127.     return;
  128.     }
  129.  
  130.     /* Clip. */
  131.     cx0 = x0;
  132.     cy0 = y0;
  133.     cx1 = x1;
  134.     cy1 = y1;
  135.     if ( ppmd_lineclip )
  136.     {
  137.     if ( cx0 < 0 )
  138.         {
  139.         if ( cx1 < 0 ) return;
  140.         cy0 = cy0 + ( cy1 - cy0 ) * ( -cx0 ) / ( cx1 - cx0 );
  141.         cx0 = 0;
  142.         }
  143.     else if ( cx0 >= cols )
  144.         {
  145.         if ( cx1 >= cols ) return;
  146.         cy0 = cy0 + ( cy1 - cy0 ) * ( cols - 1 - cx0 ) / ( cx1 - cx0 );
  147.         cx0 = cols - 1;
  148.         }
  149.     if ( cy0 < 0 )
  150.         {
  151.         if ( cy1 < 0 ) return;
  152.         cx0 = cx0 + ( cx1 - cx0 ) * ( -cy0 ) / ( cy1 - cy0 );
  153.         cy0 = 0;
  154.         }
  155.     else if ( cy0 >= rows )
  156.         {
  157.         if ( cy1 >= rows ) return;
  158.         cx0 = cx0 + ( cx1 - cx0 ) * ( rows - 1 - cy0 ) / ( cy1 - cy0 );
  159.         cy0 = rows - 1;
  160.         }
  161.     if ( cx1 < 0 )
  162.         {
  163.         cy1 = cy1 + ( cy0 - cy1 ) * ( -cx1 ) / ( cx0 - cx1 );
  164.         cx1 = 0;
  165.         }
  166.     else if ( cx1 >= cols )
  167.         {
  168.         cy1 = cy1 + ( cy0 - cy1 ) * ( cols - 1 - cx1 ) / ( cx0 - cx1 );
  169.         cx1 = cols - 1;
  170.         }
  171.     if ( cy1 < 0 )
  172.         {
  173.         cx1 = cx1 + ( cx0 - cx1 ) * ( -cy1 ) / ( cy0 - cy1 );
  174.         cy1 = 0;
  175.         }
  176.     else if ( cy1 >= rows )
  177.         {
  178.         cx1 = cx1 + ( cx0 - cx1 ) * ( rows - 1 - cy1 ) / ( cy0 - cy1 );
  179.         cy1 = rows - 1;
  180.         }
  181.  
  182.     /* Check again for zero-length lines. */
  183.     if ( cx0 == cx1 && cy0 == cy1 )
  184.         {
  185.         if ( drawprocP == PPMD_NULLDRAWPROC )
  186.         ppmd_point_drawproc(
  187.             pixels, cols, rows, maxval, cx0, cy0, clientdata );
  188.         else
  189.         (*drawprocP)(
  190.             pixels, cols, rows, maxval, cx0, cy0, clientdata );
  191.         return;
  192.         }
  193.     }
  194.  
  195.     /* Draw, using a simple DDA. */
  196.     if ( abs( cx1 - cx0 ) > abs( cy1 - cy0 ) )
  197.     { /* Loop over X domain. */
  198.     register long dy, srow;
  199.     register int dx, col, row, prevrow;
  200.  
  201.     if ( cx1 > cx0 )
  202.         dx = 1;
  203.     else
  204.         dx = -1;
  205.     dy = ( cy1 - cy0 ) * DDA_SCALE / abs( cx1 - cx0 );
  206.     prevrow = row = cy0;
  207.     srow = row * DDA_SCALE + DDA_SCALE / 2;
  208.     col = cx0;
  209.     for ( ; ; )
  210.         {
  211.         if ( ppmd_linetype == PPMD_LINETYPE_NODIAGS && row != prevrow )
  212.         {
  213.         if ( drawprocP == PPMD_NULLDRAWPROC )
  214.             pixels[prevrow][col] = *( (pixel *) clientdata );
  215.         else
  216.             (*drawprocP)(
  217.                 pixels, cols, rows, maxval, col, prevrow, clientdata );
  218.         prevrow = row;
  219.         }
  220.         if ( drawprocP == PPMD_NULLDRAWPROC )
  221.         pixels[row][col] = *( (pixel *) clientdata );
  222.         else
  223.         (*drawprocP)(
  224.             pixels, cols, rows, maxval, col, row, clientdata );
  225.         if ( col == cx1 )
  226.         break;
  227.         srow += dy;
  228.         row = srow / DDA_SCALE;
  229.         col += dx;
  230.         }
  231.     }
  232.     else
  233.     { /* Loop over Y domain. */
  234.     register long dx, scol;
  235.     register int dy, col, row, prevcol;
  236.  
  237.     if ( cy1 > cy0 )
  238.         dy = 1;
  239.     else
  240.         dy = -1;
  241.     dx = ( cx1 - cx0 ) * DDA_SCALE / abs( cy1 - cy0 );
  242.     row = cy0;
  243.     prevcol = col = cx0;
  244.     scol = col * DDA_SCALE + DDA_SCALE / 2;
  245.     for ( ; ; )
  246.         {
  247.         if ( ppmd_linetype == PPMD_LINETYPE_NODIAGS && col != prevcol )
  248.         {
  249.         if ( drawprocP == PPMD_NULLDRAWPROC )
  250.             pixels[row][prevcol] = *( (pixel *) clientdata );
  251.         else
  252.             (*drawprocP)(
  253.             pixels, cols, rows, maxval, prevcol, row, clientdata );
  254.         prevcol = col;
  255.         }
  256.         if ( drawprocP == PPMD_NULLDRAWPROC )
  257.         pixels[row][col] = *( (pixel *) clientdata );
  258.         else
  259.         (*drawprocP)(
  260.             pixels, cols, rows, maxval, col, row, clientdata );
  261.         if ( row == cy1 )
  262.         break;
  263.         row += dy;
  264.         scol += dx;
  265.         col = scol / DDA_SCALE;
  266.         }
  267.     }
  268.     }
  269.  
  270. #define SPLINE_THRESH 3
  271. void
  272. ppmd_spline3( pixels, cols, rows, maxval, x0, y0, x1, y1, x2, y2, drawprocP, clientdata )
  273. pixel **pixels;
  274. int cols, rows, x0, y0, x1, y1, x2, y2;
  275. pixval maxval;
  276. void (*drawprocP)();
  277. char *clientdata;
  278.     {
  279.     register int xa, ya, xb, yb, xc, yc, xp, yp;
  280.  
  281.     xa = ( x0 + x1 ) / 2;
  282.     ya = ( y0 + y1 ) / 2;
  283.     xc = ( x1 + x2 ) / 2;
  284.     yc = ( y1 + y2 ) / 2;
  285.     xb = ( xa + xc ) / 2;
  286.     yb = ( ya + yc ) / 2;
  287.  
  288.     xp = ( x0 + xb ) / 2;
  289.     yp = ( y0 + yb ) / 2;
  290.     if ( abs( xa - xp ) + abs( ya - yp ) > SPLINE_THRESH )
  291.     ppmd_spline3(
  292.         pixels, cols, rows, maxval, x0, y0, xa, ya, xb, yb, drawprocP, clientdata );
  293.     else
  294.     ppmd_line(
  295.         pixels, cols, rows, maxval, x0, y0, xb, yb, drawprocP, clientdata );
  296.  
  297.     xp = ( x2 + xb ) / 2;
  298.     yp = ( y2 + yb ) / 2;
  299.     if ( abs( xc - xp ) + abs( yc - yp ) > SPLINE_THRESH )
  300.     ppmd_spline3(
  301.         pixels, cols, rows, maxval, xb, yb, xc, yc, x2, y2, drawprocP,
  302.         clientdata );
  303.     else
  304.     ppmd_line(
  305.         pixels, cols, rows, maxval, xb, yb, x2, y2, drawprocP, clientdata );
  306.     }
  307.  
  308. void
  309. ppmd_polyspline( pixels, cols, rows, maxval, x0, y0, nc, xc, yc, x1, y1, drawprocP, clientdata )
  310. pixel **pixels;
  311. int cols, rows, x0, y0, nc, *xc, *yc, x1, y1;
  312. pixval maxval;
  313. void (*drawprocP)();
  314. char *clientdata;
  315.     {
  316.     register int i, x, y, xn, yn;
  317.  
  318.     x = x0;
  319.     y = y0;
  320.     for ( i = 0; i < nc - 1; i++ )
  321.     {
  322.     xn = ( xc[i] + xc[i + 1] ) / 2;
  323.     yn = ( yc[i] + yc[i + 1] ) / 2;
  324.     ppmd_spline3(
  325.         pixels, cols, rows, maxval, x, y, xc[i], yc[i], xn, yn, drawprocP,
  326.         clientdata );
  327.     x = xn;
  328.     y = yn;
  329.     }
  330.     ppmd_spline3(
  331.     pixels, cols, rows, maxval, x, y, xc[nc - 1], yc[nc - 1], x1, y1,
  332.     drawprocP, clientdata );
  333.     }
  334.  
  335. void
  336. ppmd_circle( pixels, cols, rows, maxval, cx, cy, radius, drawprocP, clientdata )
  337. pixel **pixels;
  338. int cols, rows, cx, cy, radius;
  339. pixval maxval;
  340. void (*drawprocP)();
  341. char *clientdata;
  342.     {
  343.     register int x0, y0, x, y, prevx, prevy, nopointsyet;
  344.     register long sx, sy, e;
  345.  
  346.     x0 = x = radius;
  347.     y0 = y = 0;
  348.     sx = x * DDA_SCALE + DDA_SCALE / 2;
  349.     sy = y * DDA_SCALE + DDA_SCALE / 2;
  350.     e = DDA_SCALE / radius;
  351.     if ( drawprocP == PPMD_NULLDRAWPROC )
  352.     pixels[y + cy][x + cx] = *( (pixel *) clientdata );
  353.     else
  354.     (*drawprocP)( pixels, cols, rows, maxval, x + cx, y + cy, clientdata );
  355.     nopointsyet = 1;
  356.     do
  357.     {
  358.     prevx = x;
  359.     prevy = y;
  360.     sx += e * sy / DDA_SCALE;
  361.     sy -= e * sx / DDA_SCALE;
  362.     x = sx / DDA_SCALE;
  363.     y = sy / DDA_SCALE;
  364.     if ( x != prevx || y != prevy )
  365.         {
  366.         nopointsyet = 0;
  367.         if ( drawprocP == PPMD_NULLDRAWPROC )
  368.         pixels[y + cy][x + cx] = *( (pixel *) clientdata );
  369.         else
  370.         (*drawprocP)(
  371.             pixels, cols, rows, maxval, x + cx, y + cy, clientdata );
  372.         }
  373.     }
  374.     while ( nopointsyet || x != x0 || y != y0 );
  375.     }
  376.  
  377.  
  378. /* Arbitrary fill stuff. */
  379.  
  380. typedef struct
  381.     {
  382.     int x;
  383.     int y;
  384.     } coord;
  385. typedef struct
  386.     {
  387.     int n;
  388.     int size;
  389.     coord *coords;
  390.     } fillobj;
  391.  
  392. #define SOME 1000
  393.  
  394. static int oldclip;
  395.  
  396. char *
  397. ppmd_fill_init( )
  398.     {
  399.     fillobj *fh;
  400.  
  401.     fh = (fillobj *) malloc( sizeof(fillobj) );
  402.     if ( fh == 0 )
  403.     pm_error( "out of memory allocating a fillhandle", 0,0,0,0,0 );
  404.     fh->n = 0;
  405.     fh->coords = (coord *) malloc( SOME * sizeof(coord) );
  406.     if ( fh->coords == 0 )
  407.     pm_error( "out of memory allocating a fillhandle", 0,0,0,0,0 );
  408.     fh->coords[0].x = fh->coords[0].y = -27182;
  409.     fh->size = SOME;
  410.  
  411.     /* Turn off line clipping. */
  412.     oldclip = ppmd_setlineclip( 0 );
  413.     
  414.     return (char *) fh;
  415.     }
  416.  
  417. void
  418. ppmd_fill_drawproc( pixels, cols, rows, maxval, x, y, clientdata )
  419. pixel **pixels;
  420. int cols, rows, x, y;
  421. pixval maxval;
  422. char *clientdata;
  423.     {
  424.     register fillobj *fh;
  425.     register coord *cp;
  426.  
  427.     fh = (fillobj *) clientdata;
  428.     cp = &(fh->coords[fh->n]);
  429.  
  430.     /* If these are the same coords we saved last time, don't bother. */
  431.     if ( x == cp->x && y == cp->y )
  432.     return;
  433.  
  434.     /* Ok, these are new; check if there's enough room. */
  435.     if ( fh->n >= fh->size )
  436.     {
  437.     fh->size += SOME;
  438.     fh->coords = (coord *) realloc(
  439.         (char *) fh->coords, fh->size * sizeof(coord) );
  440.     if ( fh->coords == 0 )
  441.         pm_error( "out of memory enlarging a fillhandle", 0,0,0,0,0 );
  442.     cp = &(fh->coords[fh->n]);
  443.     }
  444.  
  445.     /* And save 'em. */
  446.     cp->x = x;
  447.     cp->y = y;
  448.     fh->n++;
  449.     }
  450.  
  451. void
  452. ppmd_fill( pixels, cols, rows, maxval, fillhandle, drawprocP, clientdata )
  453. pixel **pixels;
  454. int cols, rows;
  455. pixval maxval;
  456. char *fillhandle;
  457. void (*drawprocP)();
  458. char *clientdata;
  459.     {
  460.     register fillobj *fh;
  461.     register int i, on, px, py, col;
  462.     register coord *cp;
  463.     static int yxcompare();
  464.  
  465.     fh = (fillobj *) fillhandle;
  466.  
  467.     /* Restore clipping now. */
  468.     (void) ppmd_setlineclip( oldclip );
  469.  
  470.     /* Sort the coords by Y, and secondarily by X. */
  471.     qsort( (char *) fh->coords, fh->n, sizeof(coord), yxcompare );
  472.  
  473.     /* Ok, now run through the coords.  This code doesn't deal with
  474.     ** inflection points too well, but it would not be hard to fix. */
  475.     on = 0;
  476.     px = py = -31415;
  477.     for ( i = 0; i < fh->n; i++ )
  478.     {
  479.     cp = &(fh->coords[i]);
  480.     if ( on )
  481.         {
  482.         if ( cp->y != py )
  483.         { /* Broken span.  Hmm.  Start a new one. */
  484.         px = cp->x;
  485.         py = cp->y;
  486.         }
  487.         else
  488.         if ( cp->x <= px + 1 )
  489.             { /* Not an end-of-span, but a continuation of the start. */
  490.             if ( py >= 0 && py < rows && px >= 0 && px < cols )
  491.             if ( drawprocP == PPMD_NULLDRAWPROC )
  492.                 pixels[py][px] = *( (pixel *) clientdata );
  493.             else
  494.                 (*drawprocP)(
  495.                 pixels, cols, rows, maxval, px, py,
  496.                 clientdata );
  497.             px = cp->x;
  498.             }
  499.         else
  500.             { /* Got a span to fill.  But clip it first. */
  501.             if ( py >= 0 && py < rows )
  502.             {
  503.             if ( px < 0 )
  504.                 px = 0;
  505.             if ( cp->x >= cols )
  506.                 cp->x = cols - 1;
  507.             if ( px <= cp->x )
  508.                 for ( col = px; col <= cp->x; col++ )
  509.                 if ( drawprocP == PPMD_NULLDRAWPROC )
  510.                     pixels[py][col] = *( (pixel *) clientdata );
  511.                 else
  512.                     (*drawprocP)(
  513.                     pixels, cols, rows, maxval, col, py,
  514.                     clientdata );
  515.             }
  516.             px = cp->x;
  517.             on = 0;
  518.             }
  519.         }
  520.     else
  521.         {
  522.         if ( cp->y == py && cp->x <= px + 1 )
  523.         { /* Not a start-of-span, but a continuation of the end. */
  524.         px = cp->x;
  525.         if ( py >= 0 && py < rows && px >= 0 && px < cols )
  526.             if ( drawprocP == PPMD_NULLDRAWPROC )
  527.             pixels[py][px] = *( (pixel *) clientdata );
  528.             else
  529.             (*drawprocP)(
  530.                 pixels, cols, rows, maxval, px, py, clientdata );
  531.         }
  532.         else
  533.         {
  534.         px = cp->x;
  535.         py = cp->y;
  536.         on = 1;
  537.         }
  538.         }
  539.     }
  540.  
  541.     /* All done.  Free up the fillhandle and leave. */
  542.     free( fh->coords );
  543.     free( fh );
  544.     }
  545.  
  546. static int
  547. yxcompare( c1, c2 )
  548. coord *c1, *c2;
  549.     {
  550.     if ( c1->y > c2->y )
  551.     return 1;
  552.     if ( c1->y < c2->y )
  553.     return -1;
  554.     if ( c1->x > c2->x )
  555.     return 1;
  556.     if ( c1->x < c2->x )
  557.     return -1;
  558.     return 0;
  559.     }
  560.