/* WARNING: the code below assumes 640x350 16-color ega */

/* 0=black	1=blue		2=green		3=light blue		*/
/* 4=red	5=purple	6=brown		7=grey			*/
/* 8=black	9=bright blue	A=bright green	B=bright light blue	*/
/* C=scarlet	D=purple	E=yellow	F=white			*/

#define T	0x9	/* trace color; bright blue	*/

/* screen limits; we don't draw on the very edge pixels */
#define MINHORZ	0	/* left-most pixel	*/
#define MAXHORZ	639	/* right-most pixel	*/
#define MINVERT	0	/* top-most pixel	*/
#define MAXVERT	349	/* bottom-most pixel	*/

extern void Dot( int, int, int );

void Line( int, int, int, int, int );

/*
** it is assumed that at least some part of the line must be drawn.
** whoever calls Line should ensure that this is the case, or refrain
** from making the call. otherwise, lots of time can be wasted on a
** line that is not even in the viewing window.
*/

/*
** NOTE: the screen origin is in the upper left-hand corner, not in
** the lower left-hand corner, as you would normally think of an
** (x,y) graph.
*/

void Line ( r1, c1, r2, c2, endpt ) /* draw a line between two points */
	int r1, c1, r2, c2, endpt; /* pixel rows and columns */
	{
	int i, j, rdelta, cdelta, acc, frac, aux;

/*printf("Line(r1=%d,c1=%d,r2=%d,c2=%d,endpt=%d)\n",r1,c1,r2,c2,endpt);*/
	if (endpt) { /* draw the two endpoints */
		if (r1 >= MINVERT && r1 <= MAXVERT
			&& c1 >= MINHORZ && c1 <= MAXHORZ)
			Dot( T, r1, c1 );
		if (r2 >= MINVERT && r2 <= MAXVERT
			&& c2 >= MINHORZ && c2 <= MAXHORZ)
			Dot( T, r2, c2 );
		}
	/* get leftmost endpoint into (r1,c1); swap if necessary */
	if (c2 < c1) {
		aux = c1;  c1 = c2;  c2 = aux;
		aux = r1;  r1 = r2;  r2 = aux;
		}
	if (c1 == c2) { /* vertical line */
		if (c1 >= MINHORZ && c1 <= MAXHORZ) {
			if (r1 < r2) { /* (r1,c1) is on top */
				for (i = r1+1; i < r2; i++)
					if (i >= MINVERT && i <= MAXVERT)
						Dot( T, i, c1 );
				}
			else { /* (r2,c2) is on top */
				for (i = r1-1; i > r2; i--)
					if (i >= MINVERT && i <= MAXVERT)
						Dot( T, i, c1 );
				}
			}
		}
	else if (r1 == r2) { /* horizontal line */
		if (r1 >= MINVERT && r1 <= MAXVERT)
			for (i = c1+1; i < c2; i++)
				if (i >= MINHORZ && i <= MAXHORZ)
					Dot( T, r1, i );
		}
	else { /* line running from left to right: (r1,c1) -> (r2,c2) */
		rdelta = r2-r1; /* positive or negative */
		cdelta = c2-c1; /* always non-negative */
		if (rdelta == cdelta) { /* line has slope of -1 */
			for (i = r1+1, j = c1+1; i < r2 && j < c2; i++, j++)
				if (i >= MINVERT && i <= MAXVERT
					&& j >= MINHORZ && j <= MAXHORZ)
					Dot( T, i, j );
			}
		else if (-rdelta == cdelta) { /* line has slope of +1 */
			for (i = r1-1, j = c1+1; i > r2 && j < c2; i--, j++)
				if (i >= MINVERT && i <= MAXVERT
					&& j >= MINHORZ && j <= MAXHORZ)
					Dot( T, i, j );
			}
		/*
		** find out which sector the line is in:
		**
		** MINVERT
		**		(rdelta negative)
		**    |      /
		**    | 1  /
		**    |  /
		**   \|/   2
		**   -*-------
		**   /|\   3
		**    |  \
		**    | 4  \
		**    |      \
		**		(rdelta positive)
		** MAXVERT
		*/
		else if (rdelta < 0) { /* positive slope */
			rdelta = -rdelta;
			if (rdelta > cdelta) { /* sector 1 */
				for (i = r1-1, acc = 0, frac = cdelta;
					i > r2; i--, frac += cdelta) {
					if (frac >= rdelta) {
						acc++;
						frac -= rdelta;
						}
					aux = (frac+frac >= rdelta) ? 1 : 0;
					if (i >= MINVERT && i <= MAXVERT
						&& (j = c1+acc+aux) >= MINHORZ
						&& j <= MAXHORZ)
						Dot( T, i, j );
					}
				}
			else { /* sector 2 */
				for (j = c1+1, acc = 0, frac = rdelta;
					j < c2; j++, frac += rdelta) {
					if (frac >= cdelta) {
						acc++;
						frac -= cdelta;
						}
					aux = (frac+frac >= cdelta) ? 1 : 0;
					if ((i = r1-acc-aux) >= MINVERT
						&& i <= MAXVERT
						&& j >= MINHORZ
						&& j <= MAXHORZ)
						Dot( T, i, j );
					}
				}
			}
		else { /* negative slope */
			if (rdelta < cdelta) { /* sector 3 */
				for (j = c1+1, acc = 0, frac = rdelta;
					j < c2; j++, frac += rdelta) {
					if (frac >= cdelta) {
						acc++;
						frac -= cdelta;
						}
					aux = (frac+frac >= cdelta) ? 1 : 0;
					if ((i = r1+acc+aux) >= MINVERT
						&& i <= MAXVERT
						&& j >= MINHORZ
						&& j <= MAXHORZ)
						Dot( T, i, j );
					}
				}
			else { /* sector 4 */
				for (i = r1+1, acc = 0, frac = cdelta;
					i < r2; i++, frac += cdelta) {
					if (frac >= rdelta) {
						acc++;
						frac -= rdelta;
						}
					aux = (frac+frac >= rdelta) ? 1 : 0;
					if (i >= MINVERT && i <= MAXVERT
						&& (j = c1+acc+aux) >= MINHORZ
						&& j <= MAXHORZ)
						Dot( T, i, j );
					}
				}
			}
		}
	}
