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 >
Wrap
C/C++ Source or Header
|
1989-11-20
|
11KB
|
418 lines
/*
* GRAPH, Version 1.00 - 4 August 1989
*
* Copyright 1989, David Gay. All Rights Reserved.
* This software is freely redistrubatable.
*/
/* Various graphic extensions */
#include <exec/types.h>
#include <graphics/rastport.h>
#include <math.h>
#include <string.h>
#include "graphics.h"
#include <proto/graphics.h>
/* 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;
}