home *** CD-ROM | disk | FTP | other *** search
- /*
- * lemvec.c - line to point scan conversion
- *
- * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
- */
-
- /*
- *
- * Programmed by Alan Paeth, University of Waterloo, January, 1984
- *
- * This code rasterizes vectors. A call of the form:
- *
- * drawline(x0, y0, x1, y1, wid, val, emph)
- *
- * with val the output color, and emph one of EMPHITAL, EMPHBOLD, (otherwise)
- * generates a vector of specified which is dotted, dashed, or plain,
- * respectively.
- *
- * output pixels are set by calls to:
- *
- * setpixelrun(x, y, wid, val, parity)
- *
- * which should set pixels (x,y) through (x+wid-1,y) to color (val) if
- * parity is 0 (as it is at endpoints and some intermediate locations).
- *
- * viewport clipping is done (using integer math) to the dimensions specified
- * in the globals "screenw" and "screenh"
- *
- */
-
- #include "lem.h"
-
- #define Nextflag { mask>>=1; if (++flag >= 16) { flag = 0; mask = emph; } }
-
- #define SOLID 0xffffffff /* only solid should have sign bit set */
- #define DASHES 0x00ff00ff
- #define DOTS 0x03030303
-
- #define ONE 0x4000
- #define POINT_FIVE 0x2000
- #define SCALEUP 14
-
- #define TOPFLAG 8
- #define BOTTOMFLAG 4
- #define LEFTFLAG 2
- #define RIGHTFLAG 1
-
- code(x, y)
- float x, y;
- {
- int c = 0;
- if (x < 0) c |= LEFTFLAG; else if (x >= screenw) c |= RIGHTFLAG;
- if (y < 0) c |= BOTTOMFLAG; else if (y >= screenh) c |= TOPFLAG;
- return c;
- }
-
- drawline(x1, y1, x2, y2, wid, val, emph) /* generic brand clipped line code */
- {
- int c, c1, c2;
- long x, y;
-
- if ((x1==x2) && (y1==y2)) return; /* no motion -- fast return */
-
- c1 = code((float)(x1), (float)(y1));
- c2 = code((float)(x2), (float)(y2));
-
- while (c1 || c2)
- {
- if (c1 & c2) return; /* bitwise AND, not statement AND */
- c = c1 ? c1 : c2;
-
- if (c & LEFTFLAG)
- y = y1 + ((y2 - y1) * ( (x = 0) - x1)) / (x2 - x1);
- else if (c & RIGHTFLAG)
- y = y1 + ((y2 - y1) * ( (x = screenw) - x1)) / (x2 - x1);
- else if (c & TOPFLAG)
- x = x1 + ((x2 - x1) * ( (y = screenh) - y1)) / (y2 - y1);
- else if (c & BOTTOMFLAG)
- x = x1 + ((x2 - x1) * ( (y = 0) - y1)) / (y2 - y1);
-
- if (c == c1)
- {
- x1 = x;
- y1 = y;
- c1 = code(x, y);
- }
- else
- {
- x2 = x;
- y2 = y;
- c2 = code(x, y);
- }
- }
- fastdrawline(x1, y1, x2, y2, wid, val, emph);
- }
-
- fastdrawline(x1, y1, x2, y2, wid, val, emph)
-
- /*
- *
- * Draws a line of pixels=val from (x1, y1) to (x2, y2) very fast.
- *
- * This is algorithm A1 from "Filtering Edges for Grey-Scale Displays" by
- * Gupta & Sproull (Computer Graphics 15,3 August 1981). No anti-aliasing
- * is being done here. However the variable 'v' can be * used to turn on
- * pixels to the left and right (above and below) the line since v is
- * horizontal distance from the center of the line to the pixel at (x, y).
- *
- * Last Hacked by: Alan Paeth
- */
-
- int x1, y1, x2, y2, val, emph;
- {
- register x, y; /* current position in line */
- int incr; /* y increment = + or - 1 */
- int dx, dy; /* change in x, y */
- int m; /* slope of line ( * 2 ** 14 ) */
- int s; /* threshold for diagonal move */
- register v; /* dist from line to pixel */
- int mm1; /* m - (1 << 9) */
- int mask;
- int flag;
-
- flag = 0;
- emph = (emph == EMPHITAL) ? DOTS : ((emph == EMPHBOLD) ? DASHES : SOLID);
- mask = emph;
-
- if (y2 > y1) /* make y1 > y2 by symmetries */
- {
- x = x1; x1 = x2; x2 = x;
- y = y1; y1 = y2; y2 = y;
- }
-
- incr = 1;
- dy = y1 - y2;
-
- if ((dx = x2 - x1) < 0)
- {
- dx = -dx;
- incr = -1;
- }
-
- v = 0;
- if (dx > dy)
- {
- m = ((long)dy << SCALEUP) / (long)dx;
- s = POINT_FIVE - m;
- mm1 = m - ONE;
- y = y1;
-
- for( x = x1; x != x2; x += incr )
- {
- if (mask & 0x1) setpixelrunv(x, y, wid, val, flag & 0x1);
- Nextflag;
- if( v >= s ) { --y; v += mm1; } /* diagonal move */
- else v += m; /* horizontal move */
- }
- setpixelrunv(x, y, wid, val, 0);
- }
- else
- {
- if( dy > 0 )
- {
- m = ((long)dx << SCALEUP) / (long)dy;
- s = POINT_FIVE - m;
- mm1 = m - ONE;
- }
- x = x1;
-
- for( y = y1; y > y2; --y )
- {
- if (mask & 0x1) setpixelrunh(x, y, wid, val, flag&0x1);
- Nextflag;
- if ( v >= s ) { x += incr; v += mm1; } /* diagonal move */
- else v += m; /* vertical move */
- }
- setpixelrunh(x, y, wid, val, 0);
- }
- }
-