home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff280.lzh / Graph / graphics.c < prev    next >
C/C++ Source or Header  |  1989-11-20  |  11KB  |  418 lines

  1. /*
  2.  *                 GRAPH, Version 1.00 - 4 August 1989
  3.  *
  4.  *            Copyright 1989, David Gay. All Rights Reserved.
  5.  *            This software is freely redistrubatable.
  6.  */
  7.  
  8. /* Various graphic extensions */
  9. #include <exec/types.h>
  10. #include <graphics/rastport.h>
  11. #include <math.h>
  12. #include <string.h>
  13.  
  14. #include "graphics.h"
  15.  
  16. #include <proto/graphics.h>
  17.  
  18. /* Size limit for std routines */
  19. #define MAXPIXELS 1007
  20.  
  21. /* Draws very long lines */
  22. void BigDraw(struct RastPort *rp, long x1, long y1)
  23. {
  24.     short x0 = rp->cp_x;
  25.     short y0 = rp->cp_y;
  26.     short dx = x1 - x0;
  27.     short dy = y1 - y0;
  28.  
  29.     if (rp->PenWidth > 1 || rp->PenHeight > 1)
  30.         ThickDraw(rp, x1, y1);
  31.     else
  32.     {
  33.         if (dx < 0) dx = -dx;
  34.         if (dy < 0) dy = -dy;
  35.  
  36.         /* Use std routine if possible. It's 10 (or is it 100) x faster ! */
  37.         if (dx <= MAXPIXELS && dy <= MAXPIXELS ||
  38.             rp->BitMap->BytesPerRow <= (MAXPIXELS >> 3) && rp->BitMap->Rows <=
  39. MAXPIXELS)
  40.             Draw(rp, x1, y1);
  41.  
  42.         else if (dx == 0) /* Vertical line */
  43.         {
  44.             if (y0 < y1)
  45.                 do Draw(rp, x1, y0 = min(y0 + MAXPIXELS, y1)); while (y0 != y1)
  46. ;
  47.             else
  48.                 do Draw(rp, x1, y0 = max(y0 - MAXPIXELS, y1)); while (y0 != y1)
  49. ;
  50.         }
  51.         else if (dy == 0) /* Horizontal line */
  52.         {
  53.             if (x0 < x1)
  54.                 do Draw(rp, x0 = min(x0 + MAXPIXELS, x1), y1); while (x0 != x1)
  55. ;
  56.             else
  57.                 do Draw(rp, x0 = max(x0 - MAXPIXELS, x1), y1); while (x0 != x1)
  58. ;
  59.         }
  60.         else /* "Standard" line drawing routine, with shifts. Could be recoded
  61.                 in assembly, but as most time is spent in WritePixel, this
  62.                 wouldn't help much. Probably faster to work out where to
  63.                 break the line to be able to use the std draw routine (even
  64.                 using real arithmetic). However, is rarely used, so ... */
  65.         {
  66.             register short x, y;
  67.             register short a;
  68.             register short add1;
  69.             register short upadd;
  70.             short end, oend, inc;
  71.  
  72.             if (dx > dy) /* --> 1 pixel for each x */
  73.             {
  74.                 /* We want to start at the lowest value of x */
  75.                 if (x0 > x1)
  76.                 {
  77.                     x = x1;
  78.                     y = y1;
  79.                     end = x0;
  80.                     oend = y0;
  81.                 }
  82.                 else
  83.                 {
  84.                     x = x0;
  85.                     y = y0;
  86.                     end = x1;
  87.                     oend = y1;
  88.                 }
  89.  
  90.                 inc =  (oend < y) ? -1 : 1; /* y direction */
  91.                 a = 2 * dy - dx;            /* initial "error" */
  92.                 add1 = 2 * dy;              /* Standard increment */
  93.                 upadd = 2 * dy - 2 * dx;    /* Pixel increment */
  94.  
  95.                 while (x <= end)
  96.                 {
  97.                     WritePixel(rp, x, y);
  98.  
  99.                     if (a > 0) /* A y shift ! */
  100.                     {
  101.                         a += upadd;
  102.                         y += inc;
  103.                     }
  104.                     else
  105.                         a += add1;
  106.  
  107.                     x += 1;
  108.                 }
  109.             }
  110.             else /* 1 pixel for each y */
  111.             {
  112.                 if (y0 > y1)
  113.                 {
  114.                     y = y1;
  115.                     x = x1;
  116.                     end = y0;
  117.                     oend = x0;
  118.                 }
  119.                 else
  120.                 {
  121.                     y = y0;
  122.                     x = x0;
  123.                     end = y1;
  124.                     oend = x1;
  125.                 }
  126.  
  127.                 inc =  (oend < x) ? -1 : 1;
  128.                 a = 2 * dx - dy;
  129.                 add1 = 2 * dx;
  130.                 upadd = 2 * dx - 2 * dy;
  131.  
  132.                 while (y <= end)
  133.                 {
  134.                     WritePixel(rp, x, y);
  135.  
  136.                     if (a > 0)
  137.                     {
  138.                         a += upadd;
  139.                         x += inc;
  140.                     }
  141.                     else
  142.                         a += add1;
  143.  
  144.                     y += 1;
  145.                 }
  146.             }
  147.             rp->cp_x = x1;
  148.             rp->cp_y = y1;
  149.         }
  150.     }
  151. }
  152.  
  153. /* Only for RastPort's with no clipping ! */
  154. void BigSetRast(struct RastPort *rp, long colour)
  155. {
  156.     struct BitMap *bm = rp->BitMap;
  157.     int i;
  158.  
  159.     for (i = 0; i < bm->Depth; i++, colour = colour >> 1)
  160.         memset(bm->Planes[i], colour & 1 ? 255 : 0, bm->BytesPerRow * bm->Rows)
  161. ;
  162. }
  163.  
  164. /* Determine real text extent, if written in font font */
  165. void TextExtent(char *text, struct TextFont *font, struct TextExtent *ext)
  166. {
  167.     static struct IntuiText it = {
  168.         1, 0, JAM1, 0, 0
  169.     };
  170.     struct TextAttr ta;
  171.  
  172.     ta.ta_Name = font->tf_Message.mn_Node.ln_Name;
  173.     ta.ta_YSize = font->tf_YSize;
  174.     ta.ta_Style = font->tf_Style;
  175.     ta.ta_Flags = font->tf_Flags;
  176.  
  177.     it.ITextFont = &ta;
  178.     it.IText = text;
  179.  
  180.     ext->te_Extent.MaxX = ext->te_Width = IntuiTextLength(&it) - 1;
  181.     ext->te_Height = font->tf_YSize;
  182.     ext->te_Extent.MinY = - font->tf_Baseline;
  183.     ext->te_Extent.MaxY = font->tf_YSize - font->tf_Baseline - 1;
  184.     /* The tricky part: in a proportional font, with kerning, a letter may
  185.        start gto the left of the current position. */
  186.     ext->te_Extent.MinX =
  187.        (font->tf_CharKern && (UBYTE)(text[0]) >= font->tf_LoChar && (UBYTE)(tex
  188. t[0]) <= font->tf_HiChar)
  189.            ? ((WORD *)(font->tf_CharKern))[text[0] - font->tf_LoChar]
  190.            : 0;
  191. }
  192.  
  193. /* Assumes w,h not too big ( < MAXPIXELS ) ..., w and h odd */
  194. void ThickDraw(struct RastPort *rp, long _x1, long _y1)
  195. {
  196.     short x0 = rp->cp_x;
  197.     short y0 = rp->cp_y;
  198.     short x1 = _x1;
  199.     short y1 = _y1;
  200.     short dx = x1 - x0;
  201.     short dy = y1 - y0;
  202.     short w = rp->PenWidth;
  203.     short h = rp->PenHeight;
  204.  
  205.     if (dx < 0) dx = -dx;
  206.     if (dy < 0) dy = -dy;
  207.  
  208.     if (dx == 0) /* Vertical line -> easy */
  209.     {
  210.         short x00 = x0 - w / 2;
  211.         short x01 = x0 + w / 2;;
  212.  
  213.         if (y0 < y1)
  214.         {
  215.             y0 -= h / 2;
  216.             y1 += h / 2;
  217.             do {
  218.                 short ny = min(y0 + MAXPIXELS, y1);
  219.                 RectFill(rp, x00, y0, x01, ny);
  220.                 y0 = ny;
  221.             } while (y0 != y1);
  222.         }
  223.         else
  224.         {
  225.             y1 -= h / 2;
  226.             y0 += h / 2;
  227.             do {
  228.                 short ny = max(y0 - MAXPIXELS, y1);
  229.                 RectFill(rp, x00, ny, x01, y0);
  230.                 y0 = ny;
  231.             } while (y0 != y1);
  232.         }
  233.     }
  234.     else if (dy == 0) /* Horizontal line */
  235.     {
  236.         short y00 = y0 - h / 2;
  237.         short y01 = y0 + h / 2;
  238.  
  239.         if (x0 < x1)
  240.         {
  241.             x0 -= w / 2;
  242.             x1 += w / 2;
  243.             do {
  244.                 short nx = min(x0 + MAXPIXELS, x1);
  245.                 RectFill(rp, x0, y00, nx, y01);
  246.                 x0 = nx;
  247.             } while (x0 != x1);
  248.         }
  249.         else
  250.         {
  251.             x0 += w / 2;
  252.             x1 -= w / 2;
  253.             do {
  254.                 short nx = max(x0 - MAXPIXELS, x1);
  255.                 RectFill(rp, nx, y00, x0, y01);
  256.                 x0 = nx;
  257.             } while (x0 != x1);
  258.         }
  259.     }
  260.     else /* Same algorithme as in BigDraw, the thickness is done by drawing
  261.             horiz. (or vert.) lines for each value of y (x) */
  262.     {
  263.         register short x, y;
  264.         register short a;
  265.         register short add1;
  266.         register short upadd;
  267.         short end, oend, inc;
  268.  
  269.         if (dx > dy) /* 1 pixel for each x */
  270.         {
  271.             short barh, bary0, bary1, sx;
  272.  
  273.             barh = (w * dy);
  274.             barh = barh / dx + h;
  275.  
  276.             if (x0 > x1)
  277.             {
  278.                 x = x1;
  279.                 y = y1;
  280.                 end = x0;
  281.                 oend = y0;
  282.             }
  283.             else
  284.             {
  285.                 x = x0;
  286.                 y = y0;
  287.                 end = x1;
  288.                 oend = y1;
  289.             }
  290.  
  291.             inc =  (oend < y) ? -1 : 1;
  292.             a = 2 * dy - dx;
  293.             add1 = 2 * dy;
  294.             upadd = 2 * dy - 2 * dx;
  295.  
  296.             x -= w / 2;
  297.             end += w / 2;
  298.             if (inc > 0)
  299.             {
  300.                 bary0 = y - h / 2;
  301.                 bary1 = oend + h / 2;
  302.                 y += h / 2 - barh + 1;
  303.                 oend -= h / 2;
  304.             }
  305.             else
  306.             {
  307.                 bary0 = y + h / 2;
  308.                 bary1 = oend - h / 2;
  309.                 y -= h / 2;
  310.                 oend += h / 2 - barh + 1;
  311.             }
  312.             sx = x;
  313.             while (x <= end)
  314.             {
  315.                 short y00 = y, y01 = y + barh - 1;
  316.  
  317.                 if (inc < 0)
  318.                 {
  319.                     if (x < sx + w) y01 = bary0;
  320.                     if (x > end - w) y00 = bary1;
  321.                 }
  322.                 else
  323.                 {
  324.                     if (x < sx + w) y00 = bary0;
  325.                     if (x > end - w) y01 = bary1;
  326.                 }
  327.                 Move(rp, x, y00);
  328.                 Draw(rp, x, y01);
  329.  
  330.                 if (a > 0)
  331.                 {
  332.                     a += upadd;
  333.                     y += inc;
  334.                 }
  335.                 else
  336.                     a += add1;
  337.  
  338.                 x += 1;
  339.             }
  340.         }
  341.         else /* 1 pixel for each y */
  342.         {
  343.             short barw, barx0, barx1, sy;
  344.  
  345.             barw = h * dx;
  346.             barw = w + barw / dy;
  347.  
  348.             if (y0 > y1)
  349.             {
  350.                 y = y1;
  351.                 x = x1;
  352.                 end = y0;
  353.                 oend = x0;
  354.             }
  355.             else
  356.             {
  357.                 y = y0;
  358.                 x = x0;
  359.                 end = y1;
  360.                 oend = x1;
  361.             }
  362.  
  363.             inc =  (oend < x) ? -1 : 1;
  364.             a = 2 * dx - dy;
  365.             add1 = 2 * dx;
  366.             upadd = 2 * dx - 2 * dy;
  367.  
  368.             y -= h / 2;
  369.             end += h / 2;
  370.             if (inc > 0)
  371.             {
  372.                 barx0 = x - w / 2;
  373.                 barx1 = oend + w / 2;
  374.                 x += w / 2 - barw + 1;
  375.                 oend -= w / 2;
  376.             }
  377.             else
  378.             {
  379.                 barx0 = x + w / 2;
  380.                 barx1 = oend - w / 2;
  381.                 x -= w / 2;
  382.                 oend += w / 2 - barw + 1;
  383.             }
  384.             sy = y;
  385.             while (y <= end)
  386.             {
  387.                 short x00 = x, x01 = x + barw - 1;
  388.  
  389.                 if (inc > 0)
  390.                 {
  391.                     if (y < sy + h) x00 = barx0;
  392.                     if (y > end - h) x01 = barx1;
  393.                 }
  394.                 else
  395.                 {
  396.                     if (y < sy + h) x01 = barx0;
  397.                     if (y > end - h) x00 = barx1;
  398.                 }
  399.                 Move(rp, x00, y);
  400.                 Draw(rp, x01, y);
  401.  
  402.                 if (a > 0)
  403.                 {
  404.                     a += upadd;
  405.                     x += inc;
  406.                 }
  407.                 else
  408.                     a += add1;
  409.  
  410.                 y += 1;
  411.             }
  412.         }
  413.     }
  414.     rp->cp_x = _x1;
  415.     rp->cp_y = _y1;
  416. }
  417.  
  418.