home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 13 / AACD13.ISO / AACD / Resources / System / BoingBag1 / Contributions / Workbench / RexxArpLib3p6 / src / areapolydraw.c < prev    next >
C/C++ Source or Header  |  1998-06-21  |  18KB  |  1,006 lines

  1. /** areapolydraw.c
  2.   *
  3.   *   This file contains the functions Alloc/FreeAreaInfo() and Alloc/FreeTmpRas()
  4.   *   to initialize and free TmpRas and AreaInfo structures, as well as the
  5.   *   function AreaPolyDraw(), and AddVertex() and KillVertex().
  6.   *
  7.   *   W.G.J. Langeveld, 14 July 1988
  8.   *
  9.   *   AUTHOR/DATE:  W.G.J. Langeveld, July 1988.
  10.   *   ============
  11.   *
  12.   *    CURRENT VERSION:
  13.   *
  14.   *    This version has been converted to SAS C 6.5 format. It has been modified
  15.   *    for modern definition sequences for ANSI compilation. This no longer works
  16.   *    with OS versions prior to 2.04.
  17.   *
  18.   *   AUTHOR/DATE:  Joanne Dow, jdow@bix.com, June 1998.
  19.   *   ============
  20.   *
  21.   **/
  22.  
  23. #include <functions.h>
  24. #include "ralprotos.h"
  25. #include <exec/types.h>
  26. #include <exec/exec.h>
  27. #include <intuition/intuition.h>
  28. #include <graphics/gfxmacros.h>
  29. #include <devices/timer.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33.  
  34. #include "areapolydraw.h"
  35. #include "areapatterns.h"
  36.  
  37. static int AllocAreaInfo(struct RastPort *, int);
  38. static int FreeAreaInfo(struct RastPort *);
  39. static int FindAreaSize(struct vtx *, int *, int *, int *, int *);
  40. static int setdither(unsigned int *, int);
  41. static int bm(int *, int);
  42. static struct vtx *AreaPolyClip(struct vtx *, int, int, int, int);
  43. static struct vtx *SHClip(struct vtx *, int, int);
  44. static struct vtx *addvtx(struct vtx *, struct vtx *);
  45. static int inside(struct vtx *, int, int);
  46. static struct vtx *addintersect(struct vtx *, struct vtx *,
  47. struct vtx *, int, int);
  48.  
  49. extern struct IntuitionBase *IntuitionBase;
  50. extern struct GfxBase *GfxBase;
  51.  
  52. #define AISIZE ((long) sizeof(struct AreaInfo))
  53. #define TRSIZE ((long) sizeof(struct TmpRas))
  54.     
  55. #define min(a, b) ( ((a) > (b)) ? (b) : (a) )
  56.     
  57. static int bm(), setdither(), FindAreaSize();
  58. static struct vtx *AreaPolyClip();
  59.     
  60. #define BD_LEFT   1
  61. #define BD_RIGHT  2
  62. #define BD_TOP    3
  63. #define BD_BOTTOM 4
  64.     
  65. /**
  66.  *
  67.  *    NAME
  68.  *
  69.  * AllocAreaInfo()
  70.  * ===============
  71.  *
  72.  *    SYNOPSIS
  73.  *
  74.  * AllocAreaInfo(rp, nverts)
  75.  * FreeAreaInfo(rp)
  76.  *
  77.  *    FUNCTION
  78.  *
  79.  * Function to allocate and initialize and free an AreaInfo structure
  80.  * for Area functions.
  81.  *
  82.  *    INPUTS
  83.  *
  84.  * struct RastPort *rp Rastport to be initialized
  85.  * int nverts  Number of vertices allowed
  86.  *
  87.  *    RESULT
  88.  *
  89.  * The fields in Rastport rp are initialized.
  90.  *
  91.  *    ADDITIONAL CONSIDERATIONS
  92.  *
  93.  *    BUGS
  94.  *
  95.  * None known.
  96.  *
  97.  *    AUTHOR
  98.  *
  99.  * W.G.J. Langeveld, 8 November1988
  100.  *
  101. **/
  102. static int AllocAreaInfo( struct RastPort *rp, int nverts )
  103. {
  104.     struct AreaInfo *ai = NULL;
  105.     UBYTE *aidata = NULL;
  106.     
  107.     if (ai = rp->AreaInfo) 
  108.     {
  109.         if (ai->MaxCount >= nverts)
  110.             return(1);
  111.     }
  112.     
  113.     ai = (struct AreaInfo *) AllocMem(AISIZE, MEMF_CLEAR);
  114.     if (ai == NULL)
  115.         goto cleanup;
  116.     
  117.     aidata = (UBYTE *) AllocMem((long) nverts * 5L, MEMF_CLEAR);
  118.     if (aidata == NULL)
  119.         goto cleanup;
  120.     
  121.     InitArea(ai, (WORD *) aidata, (long) nverts);
  122.     
  123.     rp->AreaInfo = ai;
  124.     
  125.     return(2);
  126.     
  127.     cleanup :
  128.     if (aidata)
  129.         FreeMem(aidata, (long) nverts * 5L);
  130.     if (ai)
  131.         FreeMem(ai,     AISIZE);
  132.     
  133.     return(0);
  134. }
  135.  
  136. static int FreeAreaInfo( struct RastPort *rp )
  137. {
  138.     struct AreaInfo *ai;
  139.     UBYTE *aidata;
  140.     
  141.     if (ai = rp->AreaInfo) 
  142.     {
  143.         if (aidata = (UBYTE *) ai->VctrTbl) 
  144.         {
  145.             FreeMem(aidata, (long) ai->MaxCount * 5L);
  146.         }
  147.         FreeMem(ai, AISIZE);
  148.         rp->AreaInfo = NULL;
  149.     }
  150.     
  151.     return(0);
  152. }
  153.  
  154.  
  155. /**
  156.  *
  157.  *    NAME
  158.  *
  159.  * AllocTmpRas()
  160.  * =============
  161.  *
  162.  *    SYNOPSIS
  163.  *
  164.  * AllocTmpRas(rp, width, height)
  165.  *
  166.  *    FUNCTION
  167.  *
  168.  * Function to allocate and initialize and free a TmpRas structure
  169.  * for Area functions.
  170.  *
  171.  *    INPUTS
  172.  *
  173.  * struct RastPort *rp Rastport to be initialized
  174.  * int width, height Size of TmpRas needed
  175.  *
  176.  *    RESULT
  177.  *
  178.  * The fields in Rastport rp are initialized.
  179.  *
  180.  *    ADDITIONAL CONSIDERATIONS
  181.  *
  182.  *    BUGS
  183.  *
  184.  * None known.
  185.  *
  186.  *    AUTHOR
  187.  *
  188.  * W.G.J. Langeveld, 24 July 1988
  189.  *
  190. **/
  191. long AllocTmpRas( struct RastPort *rp, int width, int height)
  192. {
  193.     struct TmpRas *tr = NULL;
  194.     UBYTE *trdata = NULL;
  195.     
  196.     if (tr = rp->TmpRas) 
  197.     {
  198.         if (tr->Size >= (long) RASSIZE((long) width, (long) height))
  199.             return(1);
  200.     }
  201.     
  202.     tr = (struct TmpRas *) AllocMem (TRSIZE, MEMF_CLEAR);
  203.     if (tr == NULL)
  204.         goto cleanup;
  205.     
  206.     trdata = (UBYTE *) AllocRaster((long) width, (long) height);
  207.     if (trdata == NULL)
  208.         goto cleanup;
  209.     
  210.     InitTmpRas(tr, trdata, (long) RASSIZE((long) width, (long) height) );
  211.     
  212.     rp->TmpRas = tr;
  213.     
  214.     return(2);
  215.     
  216.     cleanup :
  217.     if (trdata)
  218.         FreeRaster(trdata, (long) width, (long) height);
  219.     if (tr)
  220.         FreeMem(tr,     TRSIZE);
  221.     
  222.     return(0);
  223. }
  224.  
  225. long FreeTmpRas( struct RastPort *rp )
  226. {
  227.     struct TmpRas *tr;
  228.     
  229.     if (tr = rp->TmpRas) 
  230.     {
  231.         FreeMem(tr->RasPtr, tr->Size);
  232.         FreeMem(tr, TRSIZE);
  233.         rp->TmpRas = NULL;
  234.     }
  235.     
  236.     return(0);
  237. }
  238.  
  239. /**
  240.  *
  241.  *    NAME
  242.  *
  243.  * AreaPolyDraw()
  244.  * ==============
  245.  *
  246.  *    SYNOPSIS
  247.  *
  248.  * AreaPolyDraw(rp, vertex, ppen, xoff, yoff)
  249.  *
  250.  *    FUNCTION
  251.  *
  252.  * Draws a filled n-vertex polygon according to the outline in linked
  253.  * list of vertices. Performs pre-clipping, allows various textures and
  254.  * 4-pixel dithering patterns.
  255.  *
  256.  *    INPUTS
  257.  *
  258.  * w  Pointer to a window to receive the imagery.
  259.  *       vertex  Ptr to linked list of vtx structures
  260.  * ppen  Pattern pen. 0->15: use APen 0 through 15.
  261.  *                If texture flag set, use one of 16 textures.
  262.  *                If dither flag is set use one of 125 dithers.
  263.  *                If outline flag is set, use outline.
  264.  * xoff  X offset for polygon
  265.  * yoff  Y offset for polygon
  266.  *
  267.  *    RESULT
  268.  *
  269.  * Zero on failure, non-zero otherwise.
  270.  *
  271.  *    ADDITIONAL CONSIDERATIONS
  272.  *
  273.  * This routine allocates its own AreaInfo and TmpRas structures, and
  274.  * frees them as well. If the RastPort already had these, they are saved
  275.  * and restored at the end.
  276.  * The routine preclips all AreaMoves and AreaDraws so they won't
  277.  *       require a TmpRas larger than a single full bitplane the size of
  278.  *       the window. Window borders are taken into account.
  279.  *
  280.  *    BUGS
  281.  *
  282.  * None known.
  283.  *
  284.  *    AUTHOR
  285.  *
  286.  * W.G.J. Langeveld, 24 July 1988
  287.  *          revised: November 1989.
  288.  *
  289. **/
  290. AreaPolyDraw( struct Window *w, struct vtx *v, int ppen, int xoff, int yoff )
  291. {
  292.     register int n;
  293.     register struct vtx *tmp;
  294.     register int pow, clipped = 0;
  295.     int resai = 0, restr = 0, res = 0, notmoved, type;
  296.     struct RastPort *rp;
  297.     struct RastPort tmprp;
  298.     int minx, maxx, miny, maxy;
  299.     int clipxmin, clipymin, clipxmax, clipymax;
  300.     unsigned int colpat[64];
  301.     
  302.     if (w == NULL)
  303.         return(0);
  304.     rp = w->RPort;
  305.     
  306.     if (v == NULL)
  307.         return(0);
  308.     if (ppen & APD_NOFILL)
  309.         return(0);
  310.     /*
  311.      *   See if we need clipping
  312.      */
  313.     clipxmin =             w->BorderLeft;
  314.     clipymin =             w->BorderTop;
  315.     clipxmax = w->Width  - w->BorderRight - 1;
  316.     clipymax = w->Height - w->BorderBottom - 1;
  317.     
  318.     n = FindAreaSize(v, &minx, &miny, &maxx, &maxy);
  319.     /*
  320.      *   If so, clip the vertexlist, compute new size and set flag.
  321.      */
  322.     if ((minx < clipxmin) || (miny < clipymin) ||
  323.     (maxx > clipxmax) || (maxy > clipymax)  ) 
  324.     {
  325.         v = AreaPolyClip(v, clipxmin, clipymin, clipxmax, clipymax);
  326.         n = FindAreaSize(v, &minx, &miny, &maxx, &maxy);
  327.         clipped = 1;
  328.     }
  329.     /*
  330.      *   Check for empty set
  331.      */
  332.     if (v == NULL)
  333.         return(0);
  334.     if (n == 0)
  335.         goto cleanup;
  336.     /*
  337.      *   Make a copy of the rastport
  338.      */
  339.     movmem(rp, &tmprp, sizeof(struct RastPort));
  340.     /*
  341.      *   Add an outline if requested
  342.      */
  343.     if (ppen & APD_OUTLINE) 
  344.     {
  345.         SetOPen(&tmprp, (long) tmprp.FgPen)
  346.     }
  347.     else
  348.     {
  349.         BNDRYOFF(&tmprp);
  350.     }
  351.     /*
  352.      *   Set APen
  353.      */
  354.     if ((ppen & 0xFF) < 16)
  355.         SetAPen(&tmprp, (long) (ppen & 0xFF));
  356.     /*
  357.      *   If object still too large, just draw it, don't bother filling
  358.      */
  359.     if ((minx < clipxmin) || (miny < clipymin) ||
  360.     (maxx > clipxmax) || (maxy > clipymax)  ) 
  361.     {
  362.         tmp = v;
  363.         notmoved = 1;
  364.         while (tmp) 
  365.         {
  366.             type = tmp->type;
  367.             if (notmoved && (type == AREADRAW))
  368.                 type = AREAMOVE;
  369.             switch (type) 
  370.             {
  371.             case AREAMOVE :
  372.                 Move(&tmprp, (long) (tmp->x + xoff), (long) (tmp->y + yoff));
  373.                 notmoved = 0;
  374.                 break;
  375.             case AREADRAW :
  376.                 Draw(&tmprp, (long) (tmp->x + xoff), (long) (tmp->y + yoff) );
  377.                 break;
  378.             case AREACIRCLE :
  379.             case AREAELLIPSE :
  380.                 DrawEllipse(&tmprp, (long) (tmp->x + xoff), (long) (tmp->y + yoff),
  381.                 (long) tmp->a         , (long) tmp->b );
  382.                 break;
  383.             }
  384.             tmp = tmp->next;
  385.         }
  386.         res = 1;
  387.     }
  388.     else
  389.     {
  390.         /*
  391.          *   Allocate new AreaInfo/TmpRas (resxx = 2) or use the ones we have (resxx = 1).
  392.          */
  393.         resai = AllocAreaInfo(&tmprp, n + 10);
  394.         restr = AllocTmpRas(&tmprp, maxx - minx + 32, maxy - miny + 2);
  395.         /*
  396.          *   AreaMove, AreaDraw, AreaCircle, AreaEllipse.
  397.          */
  398.         if (resai && restr) 
  399.         {
  400.             tmp = v;
  401.             notmoved = 1;
  402.             while (tmp) 
  403.             {
  404.                 type = tmp->type;
  405.                 if (notmoved && (type == AREADRAW))
  406.                     type = AREAMOVE;
  407.                 switch (type) 
  408.                 {
  409.                 case AREAMOVE :
  410.                     AreaMove(&tmprp, (long) (tmp->x + xoff),
  411.                     (long) (tmp->y + yoff));
  412.                     notmoved = 0;
  413.                     break;
  414.                 case AREADRAW :
  415.                     AreaDraw(&tmprp, (long) (tmp->x + xoff),
  416.                     (long) (tmp->y + yoff) );
  417.                     break;
  418.                 case AREACIRCLE :
  419.                 case AREAELLIPSE :
  420.                     AreaEllipse(&tmprp, (long) (tmp->x + xoff),
  421.                     (long) (tmp->y + yoff),
  422.                     (long) tmp->a         ,
  423.                     (long) tmp->b );
  424.                     break;
  425.                 }
  426.                 tmp = tmp->next;
  427.             }
  428.             /*
  429.              *   Set up an areafill pattern
  430.              */
  431.             setmem(colpat, 128, 0);
  432.             /*
  433.              *   Copy either a texture...
  434.              */
  435.             if (ppen & APD_TEXTURE) 
  436.             {
  437.                 pow = arpt[ppen & 0xF].power;
  438.                 movmem(arpt[ppen & 0xF].data, colpat,
  439.                 (pow < 0) ? (1 << (1 - pow)) * 3 : 1 << (pow + 1));
  440.                 
  441.                 SetAfPt(&tmprp, (unsigned short *) colpat, pow); // Stop a complaint
  442.                 if (pow < 0)
  443.                     SetAPen(&tmprp, 255L);
  444.                 else
  445.                     SetAPen(&tmprp, 1L);
  446.                 SetDrMd(&tmprp, JAM2);
  447.             }
  448.             /*
  449.              *   ...or a dithered color
  450.              */
  451.             else
  452.             if (ppen & APD_DITHER) 
  453.             {
  454.                 setdither(colpat, ppen & 0xFF);
  455.                 
  456.                 SetAfPt(&tmprp, (unsigned short *) colpat, -1);
  457.                 SetAPen(&tmprp, 255L);
  458.                 SetDrMd(&tmprp, JAM2);
  459.             }
  460.             /*
  461.              *   Do the blit. Make sure the blit finishes before deallocating.
  462.              */
  463.             AreaEnd(&tmprp);
  464.             WaitBlit();
  465.             
  466.             res = 1;
  467.         }
  468.         /*
  469.          *   Free allocated resources.
  470.          */
  471.         if (resai == 2)
  472.             FreeAreaInfo(&tmprp);
  473.         if (restr == 2)
  474.             FreeTmpRas(&tmprp);
  475.     }
  476.     /*
  477.      *   Deallocate our local copy of the list
  478.      */
  479.     
  480.     cleanup:
  481.     
  482.     if (clipped)
  483.         KillVertex(v);
  484.     
  485.     return(res);
  486. }
  487.  
  488.  
  489. /**
  490.  *
  491.  *   Find number of vertices and horizontal and vertical extent.
  492.  *
  493. **/
  494. static int FindAreaSize(struct vtx *v, int *minx, int *miny, int *maxx, int *maxy )
  495. {
  496.     int n = 0, t;
  497.     
  498.     *minx = *miny = 20000;
  499.     *maxx = *maxy = 0;
  500.     
  501.     while (v) 
  502.     {
  503.         switch (v->type) 
  504.         {
  505.         case AREAMOVE :
  506.             n++;
  507.         case AREADRAW :
  508.             n++;
  509.             if ((t = v->x) < *minx)
  510.                 *minx = t;
  511.             if (t > *maxx)
  512.                 *maxx = t;
  513.             if ((t = v->y) < *miny)
  514.                 *miny = t;
  515.             if (t > *maxy)
  516.                 *maxy = t;
  517.             break;
  518.         case AREACIRCLE :
  519.             v->b = v->a;
  520.         case AREAELLIPSE :
  521.             n += 2;
  522.             if ((t = v->x - v->a) < *minx)
  523.                 *minx = t;
  524.             if ((t = v->x + v->a) > *maxx)
  525.                 *maxx = t;
  526.             if ((t = v->y - v->b) < *miny)
  527.                 *miny = t;
  528.             if ((t = v->y + v->b) > *maxy)
  529.                 *maxy = t;
  530.             break;
  531.         }
  532.         v = v->next;
  533.     }
  534.     return(n);
  535. }
  536.  
  537. /**
  538.  *
  539.  *   Allocate a new vtx structure, and add to list.
  540.  *
  541. **/
  542. struct vtx *AddVertex( struct vtx *v )
  543. {
  544.     struct vtx *t, *m;
  545.     
  546.     t = v;    // Stop compiler squawk placing it here.
  547.     if (v) 
  548.     {
  549. //        t = v;
  550.         while (t->next)
  551.             t = t->next;
  552.     }
  553.     
  554.     m = (struct vtx *) AllocMem((long) sizeof(struct vtx), MEMF_CLEAR);
  555.     
  556.     if (v)
  557.         t->next = m;
  558.     
  559.     return(m);
  560. }
  561.  
  562. /**
  563.  *
  564.  *   Delete vtx structure list.
  565.  *
  566. **/
  567. struct vtx *KillVertex( struct vtx *v )
  568. {
  569.     struct vtx *t;
  570.     
  571.     while (v) 
  572.     {
  573.         t = v->next;
  574.         FreeMem(v, (long) sizeof(struct vtx));
  575.         v = t;
  576.     }
  577.     
  578.     return(NULL);
  579. }
  580.  
  581.  
  582.  
  583. /**
  584.  *
  585.  *   This function calculates a dithering pattern for color n,
  586.  *   where n is a number between 0 and 124 (inclusive) according to
  587.  *
  588.  *      n = r * 25 + g * 5 + b,
  589.  *
  590.  *   with r, g, and b between 0 and 4 (inclusive).
  591.  *
  592. **/
  593. static unsigned int bits[16][2] = 
  594. {
  595.     {0x0000, 0x0000
  596. }
  597. ,
  598. {
  599.     0xaaaa, 0x0000
  600. }
  601. ,
  602. {
  603.     0x5555, 0x0000
  604. }
  605. ,
  606. {
  607.     0xffff, 0x0000
  608. }
  609. ,
  610. {
  611.     0x0000, 0xaaaa
  612. }
  613. ,
  614. {
  615.     0xaaaa, 0xaaaa
  616. }
  617. ,
  618. {
  619.     0x5555, 0xaaaa
  620. }
  621. ,
  622. {
  623.     0xffff, 0xaaaa
  624. }
  625. ,
  626. {
  627.     0x0000, 0x5555
  628. }
  629. ,
  630. {
  631.     0xaaaa, 0x5555
  632. }
  633. ,
  634. {
  635.     0x5555, 0x5555
  636. }
  637. ,
  638. {
  639.     0xffff, 0x5555
  640. }
  641. ,
  642. {
  643.     0x0000, 0xffff
  644. }
  645. ,
  646. {
  647.     0xaaaa, 0xffff
  648. }
  649. ,
  650. {
  651.     0x5555, 0xffff
  652. }
  653. ,
  654. {
  655.     0xffff, 0xffff
  656. }
  657. };
  658.  
  659. static int setdither( unsigned int ptdata[], int n )
  660. {
  661.     int r, g, b;
  662.     int l, m, nblack, nwhite, nmagenta, ncyan, nyellow;
  663.     static int indices[4];
  664.     static int map[4] = 
  665.     {
  666.         0, 3, 1, 2 
  667.     };
  668.     
  669.     /*
  670.      *   Argument tests
  671.      */
  672.     if (ptdata == 0L)
  673.         return;
  674.     if (n < 0)
  675.         return;
  676.     
  677.     n = (n & 0x7f);
  678.     if (n > 124)
  679.         n = 124;
  680.     /*
  681.      *   Extract r, g, and b
  682.      */
  683.     r = n / 25;
  684.     b = n - r * 25;
  685.     g = b / 5;
  686.     b = b - g * 5;
  687.     /*
  688.      *   Initialize number of black pixels in a square
  689.      */
  690.     nblack = 4;
  691.     /*
  692.      *   Number of white pixels...
  693.      */
  694.     if (nwhite = min(min(r, g), b)) 
  695.     {
  696.         r -= nwhite;
  697.         g -= nwhite;
  698.         b -= nwhite;
  699.         nblack -= nwhite;
  700.     }
  701.     /*
  702.      *   ...and cyan, magenta or yellow pixels
  703.      */
  704.     ncyan    = min(g, b);
  705.     nmagenta = min(r, b);
  706.     nyellow  = min(r, g);
  707.     
  708.     if (ncyan) 
  709.     {
  710.         g -= ncyan;
  711.         b -= ncyan;
  712.         nblack -= ncyan;
  713.     }
  714.     else
  715.     if (nmagenta) 
  716.     {
  717.         r -= nmagenta;
  718.         b -= nmagenta;
  719.         nblack -= nmagenta;
  720.     }
  721.     else
  722.     if (nyellow) 
  723.     {
  724.         r -= nyellow;
  725.         g -= nyellow;
  726.         nblack -= nyellow;
  727.     }
  728.     /*
  729.      *   ...and red green and blue pixels
  730.      */
  731.     if      (r)
  732.         nblack -= r;
  733.     else
  734.     if (g)
  735.         nblack -= g;
  736.     else
  737.     if (b)
  738.         nblack -= b;
  739.     /*
  740.      *   Set up the color indices for the four pixels
  741.      */
  742.     m = 0;
  743.     for (l = 0; l < nblack;   l++, m++)
  744.         indices[map[m]] = 0;
  745.     for (l = 0; l < nwhite;   l++, m++)
  746.         indices[map[m]] = 1;
  747.     for (l = 0; l < ncyan;    l++, m++)
  748.         indices[map[m]] = 5;
  749.     for (l = 0; l < nmagenta; l++, m++)
  750.         indices[map[m]] = 6;
  751.     for (l = 0; l < nyellow;  l++, m++)
  752.         indices[map[m]] = 7;
  753.     for (l = 0; l < r;        l++, m++)
  754.         indices[map[m]] = 2;
  755.     for (l = 0; l < g;        l++, m++)
  756.         indices[map[m]] = 3;
  757.     for (l = 0; l < b;        l++, m++)
  758.         indices[map[m]] = 4;
  759.     /*
  760.      *   Convert to bitmaps and return in ptdata.
  761.      */
  762.     movmem(bits[bm(indices, 0)], &ptdata[0], 4);
  763.     movmem(bits[bm(indices, 1)], &ptdata[2], 4);
  764.     movmem(bits[bm(indices, 2)], &ptdata[4], 4);
  765.     
  766.     return;
  767. }
  768.  
  769. /**
  770.  *
  771.  *   Extract bitmap n from quadruple s
  772.  *
  773. **/
  774. static int bm( int s[], int n )
  775. {
  776.     int index = 0;
  777.     int mask = 1 << n;
  778.     
  779.     
  780.     index = (( ((s[3] & mask) << 3) +
  781.     ((s[2] & mask) << 2) +
  782.     ((s[1] & mask) << 1) +
  783.     ((s[0] & mask)     )   ) >> n) & 0xf ;
  784.     
  785.     return(index);
  786. }
  787.  
  788. /**
  789.  *
  790.  *   Clip a vertex list against a rectangle
  791.  *
  792. **/
  793. static struct vtx *AreaPolyClip( struct vtx *vi, int x1, int y1, int x2, int y2 )
  794. {
  795.     struct vtx *vo = NULL;
  796.     
  797.     vo = SHClip(vi, BD_LEFT, x1);
  798.     /*
  799.      *   Be careful not to deallocate the input list!
  800.      */
  801.     vi = vo;
  802.     
  803.     vo = SHClip(vi, BD_RIGHT, x2);
  804.     KillVertex(vi);
  805.     vi = vo;
  806.     
  807.     vo = SHClip(vi, BD_TOP, y1);
  808.     KillVertex(vi);
  809.     vi = vo;
  810.     
  811.     vo = SHClip(vi, BD_BOTTOM, y2);
  812.     KillVertex(vi);
  813.     
  814.     return(vo);
  815. }
  816.  
  817. /**
  818.  *
  819.  *   Polygon clipping against a single boundary
  820.  *   Sutherland-Hodgman, Foley and Van dam page 454
  821.  *   Modified to do just rectangular clips.
  822.  *
  823. **/
  824. static struct vtx *SHClip( struct vtx *vi, int bordertype, int bordervalue )
  825. {
  826.     struct vtx *p, *s, *vo, *t, *u;
  827.     int first = 1;
  828.     /*
  829.      *   Find last vertex s
  830.      */
  831.     s = NULL;
  832.     
  833.     t = vi;
  834.     while (t) 
  835.     {
  836.         if (t->type == AREADRAW)
  837.             s = t;
  838.         t = t->next;
  839.     }
  840.     /*
  841.      *   If there is no last vertex, there is nothing to do
  842.      */
  843.     if (s == NULL)
  844.         return(NULL);
  845.     /*
  846.      *   Set up output vertex array
  847.      */
  848.     vo = AddVertex(NULL);
  849.     if (vo == NULL)
  850.         return(NULL);
  851.     /*
  852.      *   Loop over the list
  853.      */
  854.     while (vi) 
  855.     {
  856.         /*
  857.          *   Skip non-vertices.
  858.          */
  859.         if ((vi->type == AREAMOVE) || (vi->type == AREADRAW)) 
  860.         {
  861.             p = vi;
  862.             /*
  863.              *   Now s and p correspond to the vertices in Fig. 11.21 in
  864.              *   Foley and Van Dam
  865.              */
  866.             if (inside(p, bordertype, bordervalue)) 
  867.             {
  868.                 if (inside(s, bordertype, bordervalue)) 
  869.                 {
  870.                     addvtx(vo, p);
  871.                 }
  872.                 else
  873.                 {
  874.                     t = addintersect(vo, s, p, bordertype, bordervalue);
  875.                     u = addvtx(vo, p);
  876.                     /*
  877.                      *   Tricky: (only the first time!) if the first point is inside, but the
  878.                      *   previous point (which is the last point in the list) is outside,
  879.                      *   we want to reverse the functions of the two added points. The new
  880.                      *   intersect (t) becomes a "move", whereas the point at hand becomes a
  881.                      *   "draw" (if they were "draw" and "move" before). Reason: the intersect
  882.                      *   gets added *first*, even though it is the leftover of the *last* point.
  883.                      */
  884.                     if (first && t && u) 
  885.                     {
  886.                         if ((s->type == AREADRAW) && (p->type == AREAMOVE)) 
  887.                         {
  888.                             t->type = AREAMOVE;
  889.                             u->type = AREADRAW;
  890.                         }
  891.                     }
  892.                 }
  893.             }
  894.             else
  895.             {
  896.                 if (inside(s, bordertype, bordervalue)) 
  897.                 {
  898.                     addintersect(vo, s, p, bordertype, bordervalue);
  899.                 }
  900.             }
  901.             first = 0;
  902.             /*
  903.              *   Advance to next pair of vertices
  904.              */
  905.             s = p;
  906.         }
  907.         else
  908.         if (vi->type) 
  909.         {
  910.             /*
  911.              *   If this is something other than AREADRAW or MOVE, but not NULL,
  912.              *   copy it straight into the output.
  913.              */
  914.             addvtx(vo, vi);
  915.         }
  916.         vi = vi->next;
  917.     }
  918.     
  919.     return(vo);
  920. }
  921.  
  922. /**
  923.  *
  924.  *   Add a vertex p to list vo.
  925.  *
  926. **/
  927. static struct vtx *addvtx( struct vtx *vo, struct vtx *p )
  928. {
  929.     struct vtx *t;
  930.     
  931.     if (t = AddVertex(vo)) 
  932.     {
  933.         t->type = p->type;
  934.         t->x    = p->x;
  935.         t->y    = p->y;
  936.         t->a    = p->a;
  937.         t->b    = p->b;
  938.     }
  939.     return(t);
  940. }
  941.  
  942. /**
  943.  *
  944.  *   Determine whether a vertex is inside or outside the border
  945.  *
  946. **/
  947. static int inside( struct vtx *s, int bordertype, int bordervalue )
  948. {
  949.     if (s) 
  950.     {
  951.         switch (bordertype) 
  952.         {
  953.         case BD_LEFT :
  954.             return(s->x >= bordervalue);
  955.             break;
  956.         case BD_RIGHT :
  957.             return(s->x < bordervalue);
  958.             break;
  959.         case BD_TOP :
  960.             return(s->y >= bordervalue);
  961.             break;
  962.         case BD_BOTTOM :
  963.             return(s->y < bordervalue);
  964.             break;
  965.         }
  966.     }
  967.     return(0);
  968. }
  969.  
  970. /**
  971.  *
  972.  *   Add the intersect of vectors s and p with the border to list vo
  973.  *   Routine assumes that one vector is inside, the other outside (no
  974.  *   particular order).
  975.  *
  976. **/
  977. static struct vtx *addintersect( struct vtx *vo, struct vtx *s, struct vtx *p, int bordertype, int bordervalue )
  978. {
  979.     struct vtx *v;
  980.     
  981.     v = AddVertex(vo);
  982.     
  983.     if (s && p && v) 
  984.     {
  985.         v->type = p->type;
  986.         
  987.         switch (bordertype) 
  988.         {
  989.         case BD_LEFT :
  990.         case BD_RIGHT :
  991.             v->x = bordervalue;
  992.             v->y = s->y + (int) (((long) (bordervalue - s->x) * (p->y - s->y)) /
  993.             (p->x - s->x));
  994.             break;
  995.         case BD_TOP :
  996.         case BD_BOTTOM :
  997.             v->y = bordervalue;
  998.             v->x = s->x + (int) (((long) (bordervalue - s->y) * (p->x - s->x)) /
  999.             (p->y - s->y));
  1000.             break;
  1001.         }
  1002.     }
  1003.     return(v);
  1004. }
  1005.  
  1006.