/* * GRAPH, Version 1.00 - 4 August 1989 * * Copyright 1989, David Gay. All Rights Reserved. * This software is freely redistrubatable. */ /* Various graphic extensions */ #include #include #include #include #include "graphics.h" #include /* Size limit for std routines */ #define MAXPIXELS 1007 /* Draws very long lines */ void BigDraw(struct RastPort *rp, long x1, long y1) { short x0 = rp->cp_x; short y0 = rp->cp_y; short dx = x1 - x0; short dy = y1 - y0; if (rp->PenWidth > 1 || rp->PenHeight > 1) ThickDraw(rp, x1, y1); else { if (dx < 0) dx = -dx; if (dy < 0) dy = -dy; /* Use std routine if possible. It's 10 (or is it 100) x faster ! */ if (dx <= MAXPIXELS && dy <= MAXPIXELS || rp->BitMap->BytesPerRow <= (MAXPIXELS >> 3) && rp->BitMap->Rows <= MAXPIXELS) Draw(rp, x1, y1); else if (dx == 0) /* Vertical line */ { if (y0 < y1) do Draw(rp, x1, y0 = min(y0 + MAXPIXELS, y1)); while (y0 != y1) ; else do Draw(rp, x1, y0 = max(y0 - MAXPIXELS, y1)); while (y0 != y1) ; } else if (dy == 0) /* Horizontal line */ { if (x0 < x1) do Draw(rp, x0 = min(x0 + MAXPIXELS, x1), y1); while (x0 != x1) ; else do Draw(rp, x0 = max(x0 - MAXPIXELS, x1), y1); while (x0 != x1) ; } else /* "Standard" line drawing routine, with shifts. Could be recoded in assembly, but as most time is spent in WritePixel, this wouldn't help much. Probably faster to work out where to break the line to be able to use the std draw routine (even using real arithmetic). However, is rarely used, so ... */ { register short x, y; register short a; register short add1; register short upadd; short end, oend, inc; if (dx > dy) /* --> 1 pixel for each x */ { /* We want to start at the lowest value of x */ if (x0 > x1) { x = x1; y = y1; end = x0; oend = y0; } else { x = x0; y = y0; end = x1; oend = y1; } inc = (oend < y) ? -1 : 1; /* y direction */ a = 2 * dy - dx; /* initial "error" */ add1 = 2 * dy; /* Standard increment */ upadd = 2 * dy - 2 * dx; /* Pixel increment */ while (x <= end) { WritePixel(rp, x, y); if (a > 0) /* A y shift ! */ { a += upadd; y += inc; } else a += add1; x += 1; } } else /* 1 pixel for each y */ { if (y0 > y1) { y = y1; x = x1; end = y0; oend = x0; } else { y = y0; x = x0; end = y1; oend = x1; } inc = (oend < x) ? -1 : 1; a = 2 * dx - dy; add1 = 2 * dx; upadd = 2 * dx - 2 * dy; while (y <= end) { WritePixel(rp, x, y); if (a > 0) { a += upadd; x += inc; } else a += add1; y += 1; } } rp->cp_x = x1; rp->cp_y = y1; } } } /* Only for RastPort's with no clipping ! */ void BigSetRast(struct RastPort *rp, long colour) { struct BitMap *bm = rp->BitMap; int i; for (i = 0; i < bm->Depth; i++, colour = colour >> 1) memset(bm->Planes[i], colour & 1 ? 255 : 0, bm->BytesPerRow * bm->Rows) ; } /* Determine real text extent, if written in font font */ void TextExtent(char *text, struct TextFont *font, struct TextExtent *ext) { static struct IntuiText it = { 1, 0, JAM1, 0, 0 }; struct TextAttr ta; ta.ta_Name = font->tf_Message.mn_Node.ln_Name; ta.ta_YSize = font->tf_YSize; ta.ta_Style = font->tf_Style; ta.ta_Flags = font->tf_Flags; it.ITextFont = &ta; it.IText = text; ext->te_Extent.MaxX = ext->te_Width = IntuiTextLength(&it) - 1; ext->te_Height = font->tf_YSize; ext->te_Extent.MinY = - font->tf_Baseline; ext->te_Extent.MaxY = font->tf_YSize - font->tf_Baseline - 1; /* The tricky part: in a proportional font, with kerning, a letter may start gto the left of the current position. */ ext->te_Extent.MinX = (font->tf_CharKern && (UBYTE)(text[0]) >= font->tf_LoChar && (UBYTE)(tex t[0]) <= font->tf_HiChar) ? ((WORD *)(font->tf_CharKern))[text[0] - font->tf_LoChar] : 0; } /* Assumes w,h not too big ( < MAXPIXELS ) ..., w and h odd */ void ThickDraw(struct RastPort *rp, long _x1, long _y1) { short x0 = rp->cp_x; short y0 = rp->cp_y; short x1 = _x1; short y1 = _y1; short dx = x1 - x0; short dy = y1 - y0; short w = rp->PenWidth; short h = rp->PenHeight; if (dx < 0) dx = -dx; if (dy < 0) dy = -dy; if (dx == 0) /* Vertical line -> easy */ { short x00 = x0 - w / 2; short x01 = x0 + w / 2;; if (y0 < y1) { y0 -= h / 2; y1 += h / 2; do { short ny = min(y0 + MAXPIXELS, y1); RectFill(rp, x00, y0, x01, ny); y0 = ny; } while (y0 != y1); } else { y1 -= h / 2; y0 += h / 2; do { short ny = max(y0 - MAXPIXELS, y1); RectFill(rp, x00, ny, x01, y0); y0 = ny; } while (y0 != y1); } } else if (dy == 0) /* Horizontal line */ { short y00 = y0 - h / 2; short y01 = y0 + h / 2; if (x0 < x1) { x0 -= w / 2; x1 += w / 2; do { short nx = min(x0 + MAXPIXELS, x1); RectFill(rp, x0, y00, nx, y01); x0 = nx; } while (x0 != x1); } else { x0 += w / 2; x1 -= w / 2; do { short nx = max(x0 - MAXPIXELS, x1); RectFill(rp, nx, y00, x0, y01); x0 = nx; } while (x0 != x1); } } else /* Same algorithme as in BigDraw, the thickness is done by drawing horiz. (or vert.) lines for each value of y (x) */ { register short x, y; register short a; register short add1; register short upadd; short end, oend, inc; if (dx > dy) /* 1 pixel for each x */ { short barh, bary0, bary1, sx; barh = (w * dy); barh = barh / dx + h; if (x0 > x1) { x = x1; y = y1; end = x0; oend = y0; } else { x = x0; y = y0; end = x1; oend = y1; } inc = (oend < y) ? -1 : 1; a = 2 * dy - dx; add1 = 2 * dy; upadd = 2 * dy - 2 * dx; x -= w / 2; end += w / 2; if (inc > 0) { bary0 = y - h / 2; bary1 = oend + h / 2; y += h / 2 - barh + 1; oend -= h / 2; } else { bary0 = y + h / 2; bary1 = oend - h / 2; y -= h / 2; oend += h / 2 - barh + 1; } sx = x; while (x <= end) { short y00 = y, y01 = y + barh - 1; if (inc < 0) { if (x < sx + w) y01 = bary0; if (x > end - w) y00 = bary1; } else { if (x < sx + w) y00 = bary0; if (x > end - w) y01 = bary1; } Move(rp, x, y00); Draw(rp, x, y01); if (a > 0) { a += upadd; y += inc; } else a += add1; x += 1; } } else /* 1 pixel for each y */ { short barw, barx0, barx1, sy; barw = h * dx; barw = w + barw / dy; if (y0 > y1) { y = y1; x = x1; end = y0; oend = x0; } else { y = y0; x = x0; end = y1; oend = x1; } inc = (oend < x) ? -1 : 1; a = 2 * dx - dy; add1 = 2 * dx; upadd = 2 * dx - 2 * dy; y -= h / 2; end += h / 2; if (inc > 0) { barx0 = x - w / 2; barx1 = oend + w / 2; x += w / 2 - barw + 1; oend -= w / 2; } else { barx0 = x + w / 2; barx1 = oend - w / 2; x -= w / 2; oend += w / 2 - barw + 1; } sy = y; while (y <= end) { short x00 = x, x01 = x + barw - 1; if (inc > 0) { if (y < sy + h) x00 = barx0; if (y > end - h) x01 = barx1; } else { if (y < sy + h) x01 = barx0; if (y > end - h) x00 = barx1; } Move(rp, x00, y); Draw(rp, x01, y); if (a > 0) { a += upadd; x += inc; } else a += add1; y += 1; } } } rp->cp_x = _x1; rp->cp_y = _y1; }