readme.txt								4/27/2009


  This is an ATARI graphics library and demo.  Below are the C functions I later converted to 6502 assembly language.  You're welcome to use or modify any of this code, so I thought this might be helpful before reading the asm.  Just for fun try compiling some of this code and watch how slow C is on the 6502.

Bart Jaszcz
bpj1138@yahoo.com


// polygon set edge C routine
void set_edge(byte x, byte y, byte x1, byte y1)
{
	byte *edge;		// left/right edge select
	int dx, dy;		// x & y differences
	byte sx, sy;	// step direction flags
	int f;			// bresenham's fraction
	byte k;			// number of interations
	// check for horizontal edge
	if (y == y1)
	return;					// adjacent edges will take care of this
	// compute differences
	if (x1 > x)
	{
		sx = 1;					// positive step
		dx = (int) (x1 - x);
	}
	else
	{
		sx = 0;					// negative step
		dx = (int) (x - x1);
	}
	if (y1 > y)
	{
		sy = 1;
		dy = (int) (y1 - y);
		edge = left_edge;
	}
	else
	{
		sy = 0;
		dy = (int) (y - y1);
		edge = right_edge;
	}
	// endpoints
	edge[y] = x;
	edge[y1] = x1;
	// if x difference greater than y difference
	if (dx > dy)
	{
		k = (byte) dx >> 1;  // number of steps
		dy <<= 1;
		f = dy - dx;		// init fraction
		dx <<= 1;
		// loop until end point reached
		while (k--)
		{
			if (f >= 0)		// time to change y
			{
				if (sy)
				{
					--y1;
					++y;
				}
				else
				{
					++y1;
					--y;
				}
				f -= dx;
				edge[y] = x;
				edge[y1] = x1;
			}
			// change x every step
			if (sx)
			{
				--x1;
				++x;
			}
			else
			{
				++x1;
				--x;
			}
			f += dy;		// increment fraction
		}
	}
	else		// y diff greater than x diff
	{
		k = (byte) dy >> 1;  // number of steps
		dx <<= 1;
		f = dx - dy;		// init fraction
		dy <<= 1;
		// loop until end point reached
		while (k--)
		{
			if (f >= 0)		// time to change x
			{
				if (sx)
				{
					--x1;
					++x;
				}
				else
				{
					++x1;
					--x;
				}
				f -= dy;
			}
			// change y every step
			if (sy)
			{
				--y1;
				++y;
			}
			else
			{
				++y1;
				--y;
			}
			f += dx;		// increment fraction
			edge[y] = x;
			edge[y1] = x1;
		}
	}
}

// sometimes you need this C function, it just calls assembler plot.
void plot(byte x, byte y)
{
	*X0 = x;
	*Y0 = y;
	xy_plot_0();
}

//
// This is the Symmetric Bresenham's line function in C.
// time = 255
void draw_line(byte x, byte y, byte x1, byte y1)
{
	int dx, dy;		// x & y differences
	byte sx, sy;	// step direction flags
	int f;			// bresenham's fraction
	byte k;			// number of interations
	// compute differences
	if (x1 > x)
	{
		sx = 1;					// positive step
		dx = (int) (x1 - x);
	}
	else
	{
		sx = 0;					// negative step
		dx = (int) (x - x1);
	}
	if (y1 > y)
	{
		sy = 1;
		dy = (int) (y1 - y);
	}
	else
	{
		sy = 0;
		dy = (int) (y - y1);
	}
	// endpoints
	plot(x,y);
	plot(x1,y1);
	// if x difference greater than y difference
	if (dx > dy)
	{
		k = ((byte) dx >> 1) + 1;  // number of steps
		dy <<= 1;
		f = dy - dx;		// init fraction
		dx <<= 1;
		// loop until end point reached
		while (--k)
		{
			if (f >= 0)		// time to change y
			{
				if (sy)
				{
					--y1;
					++y;
				}
				else
				{
					++y1;
					--y;
				}
				f -= dx;
			}
			// change x every step
			if (sx)
			{
				--x1;
				++x;
			}
			else
			{
				++x1;
				--x;
			}
			plot(x,y);
			plot(x1,y1);
			f += dy;		// increment fraction
		}
	}
	else		// y diff greater than x diff
	{
		k = ((byte) dy >> 1) + 1;  // number of steps
		dx <<= 1;
		f = dx - dy;		// init fraction
		dy <<= 1;
		// loop until end point reached
		while (--k)
		{
			if (f >= 0)		// time to change x
			{
				if (sx)
				{
					--x1;
					++x;
				}
				else
				{
					++x1;
					--x;
				}
				f -= dy;
			}
			// change y every step
			if (sy)
			{
				--y1;
				++y;
			}
			else
			{
				++y1;
				--y;
			}
			plot(x,y);
			plot(x1,y1);
			f += dx;		// increment fraction
		}
	}
}
*/
/*
// time = 192
void draw_line(byte x, byte y, byte x1, byte y1)
{
	int dx, dy;		// x & y differences
	byte sx, sy;	// step direction flags
	int f;			// bresenham's fraction
	byte k;			// number of interations
	byte ix, iy, ix1, iy1;  // interative variables
	// compute differences
	if (x1 > x)
	{
		sx = 1;					// positive step
		dx = (int) (x1 - x);
	}
	else
	{
		sx = 0;					// negative step
		dx = (int) (x - x1);
	}
	if (y1 > y)
	{
		sy = 1;
		dy = (int) (y1 - y);
	}
	else
	{
		sy = 0;
		dy = (int) (y - y1);
	}
	// endpoints
	ix = x; iy = y; ix1 = x1; iy1 = y1;
	// if x difference greater than y difference
	if (dx > dy)
	{
		k = (byte) dx >> 1;  // number of steps
		dy <<= 1;
		f = dy - dx;		// init fraction
		dx <<= 1;
		// loop until end point reached
		while (k--)
		{
			// change x every step
			if (sx)
			{
				--x1;
				++x;
			}
			else
			{
				++x1;
				--x;
			}
			f += dy;		// increment fraction
			if (f >= 0)		// time to change y
			{
				if (sx)
				{
					horizontal_line(ix, x-1, y);
					horizontal_line(x1+1, ix1, y1);
				}
				else
				{
					horizontal_line(x+1, ix, y);
					horizontal_line(ix1, x1-1, y1);
				}
				ix = x;
				ix1 = x1;
				if (sy)
				{
					--y1;
					++y;
				}
				else
				{
					++y1;
					--y;
				}
				f -= dx;
			}
		}
	}
	else		// y diff greater than x diff
	{
		k = (byte) dy >> 1;  // number of steps
		dx <<= 1;
		f = dx - dy;		// init fraction
		dy <<= 1;
		// loop until end point reached
		while (k--)
		{
			// change y every step
			if (sy)
			{
				--y1;
				++y;
			}
			else
			{
				++y1;
				--y;
			}
			f += dx;		// increment fraction
			if (f >= 0)		// time to change x
			{
				if (sy)
				{
					vertical_line(x, iy, y-1);
					vertical_line(x1, y1+1, iy1);
				}
				else
				{
					vertical_line(x, y+1, iy);
					vertical_line(x1, iy1, y1-1);
				}
				iy = y;
				iy1 = y1;
				if (sx)
				{
					--x1;
					++x;
				}
				else
				{
					++x1;
					--x;
				}
				f -= dy;
			}
		}
	}
}
*/
/*
void horizontal_line(byte x, byte x1, byte y)
{
	byte *p;  // pointer
	byte i;  // counter
	byte s, e;  // byte fill start and end
	byte sr, er;  // start and end remainders 
	byte b;  // byte filled with current color
	byte m;		// bit masks for start and end remainders
	byte im;    // inverted mask
	// get scanline pointer
	p = (byte *) ((scan_high[y] << 8) + scan_low[y]);
	// get byte filled with specified color
	b = *CL;
	// calc start and end remainders
	sr = x & 3;			// x % 4 (four pixels per byte)
	er = (x1 & 3) ^ 3;		// flip the bits here
	// calc start and end of byte fill
	s = (x >> 2) + 1;
	e = x1 >> 2;
	// check for the case where x and x1 are both in the same byte
	if (e < s)
	{
		m = left_mask[sr] & right_mask[er];
		im = m ^ 0xff;
		p[e] = (p[e] & im) | (b & m);
	}
	else
	{
		// handle cases where start or end fall on byte boundries
		if (sr == 0)  // x is on byte boundry
			--s;			// increase start of byte fill
		else
		{
			m = left_mask[sr];  // get mask for start remainder pixels
			im = m ^ 0xff;   // invert mask to clear pixels in screen byte
			i = s - 1;  // get index of byte 1 to the left of byte fill start
			p[i] = (p[i] & im) | (b & m);  // set screen byte
		}
		if (er ==0)	// x1 touches next byte bounry
			++e;			// increase end of byte fill
		else
		{
			m = right_mask[er];  // get mask for end remainder pixels
			im = m ^ 0xff;   // invert mask to clear pixels in screen byte
			i = e;  // e is to the right of byte fill end already
			p[i] = (p[i] & im) | (b & m);  // set screen byte
		}
		// do the byte fill
		for (i = s; i < e; i++)
		p[i] = b;
	}
}
*/


/*
// This routine was supposedly better than bresenham's symmetric algorithm, but
// turns out to be slow on the 6502, because it has more variables, thus more swapping.
// This code also contains a bug I never resolved because of this.
// time = 258
void draw_line(byte x0, byte y0, byte x1, byte y1)
{
	int dx, dy;
	byte sx, sy;
	byte nx, ny;
	byte length;
	byte extras;
	int incr2;
	int c;
	int incr1;
	int d;
	byte i;
	
	dy = (int) y1 - (int) y0;
	dx = (int) x1 - (int) x0;

	if (dy < 0) { dy = -dy;  sy = 255; ny = 1; } else { sy = 1; ny = 255; }
	if (dx < 0) { dx = -dx;  sx = 255; nx = 1; } else { sx = 1; nx = 255; }

	plot(x0, y0);
	plot(x1, y1);
	if (dx > dy) {
		length = (dx - 1) >> 2;
		extras = (dx - 1) & 3;
		incr2 = (dy << 2) - (dx << 1);
		if (incr2 < 0) {
			c = dy << 1;
			incr1 = c << 1;
			d =  incr1 - dx;
			for (i = 0; i < length; i++) {
				x0 += sx;
				x1 += nx;
				if (d < 0) {						// Pattern:
					plot(x0, y0);			//
					plot(x0 += sx, y0);	//  x o o
					plot(x1, y1);			//
					plot(x1 += nx, y1);
					d += incr1;
				} else {
					if (d < c) {							// Pattern:
						plot(x0, y0);				//      o
						plot(x0 += sx, y0 += sy);		//  x o
						plot(x1, y1);				//
						plot(x1 += nx, y1 += ny);
					} else {
						plot(x0, y0 += sy);			// Pattern:
						plot(x0 += sx, y0);			//    o o 
						plot(x1, y1 += ny);			//  x
						plot(x1 += nx, y1);			//
					}
					d += incr2;
				}
			}
			if (extras > 0) {
				if (d < 0) {
					plot(x0 += sx, y0);
					if (extras > 1) plot(x0 += sx, y0);
					if (extras > 2) plot(x1 += nx, y1);
				} else
				if (d < c) {
					plot(x0 += sx, y0);
					if (extras > 1) plot(x0 += sx, y0 += sy);
					if (extras > 2) plot(x1 += nx, y1);
				} else {
					plot(x0 += sx, y0 += sy);
					if (extras > 1) plot(x0 += sx, y0);
					if (extras > 2) plot(x1 += nx, y1 += ny);
				}
			}
		} else {
			c = (dy - dx) << 1;
			incr1 = c << 1;
			d =  incr1 + dx;
			for (i = 0; i < length; i++) {
				x0 += sx;
				x1 += nx;
				if (d > 0) {
					plot(x0, y0 += sy);			// Pattern:
					plot(x0 += sx, y0 += sy);		//      o
					plot(x1, y1 += ny);			//    o
					plot(x1 += nx, y1 += ny);		//  x
					d += incr1;
				} else {
					if (d < c) {
						plot(x0, y0);				// Pattern:
						plot(x0 += sx, y0 += sy);       //      o
						plot(x1, y1);                         //  x o
						plot(x1 += nx, y1 += ny);       //
					} else {
						plot(x0, y0 += sy);			// Pattern:
						plot(x0 += sx, y0);			//    o o
						plot(x1, y1 += ny);			//  x
						plot(x1 += nx, y1);			//
					}
					d += incr2;
				}
			}
			if (extras > 0) {
				if (d > 0) {
					plot(x0 += sx, y0 += sy);
					if (extras > 1) plot(x0 += sx, y0 += sy);
					if (extras > 2) plot(x1 += nx, y1 += ny);
				} else
				if (d < c) {
					plot(x0 += sx, y0);
					if (extras > 1) plot(x0 += sx, y0 += sy);
					if (extras > 2) plot(x1 += nx, y1);
				} else {
					plot(x0 += sx, y0 += sy);
					if (extras > 1) plot(x0 += sx, y0);
					if (extras > 2) {
						if (d > c)
						plot(x1 += nx, y1 += ny);
						else
						plot(x1 += nx, y1);
					}
				}
			}
		}
	} else {
		length = (dy - 1) >> 2;
		extras = (dy - 1) & 3;
		incr2 = (dx << 2) - (dy << 1);
		if (incr2 < 0) {
			c = dx << 1;
			incr1 = c << 1;
			d =  incr1 - dy;
			for (i = 0; i < length; i++) {
				y0 += sy;
				y1 += ny;
				if (d < 0) {
					plot(x0, y0);
					plot(x0, y0 += sy);
					plot(x1, y1);
					plot(x1, y1 += ny);
					d += incr1;
				} else {
					if (d < c) {
						plot(x0, y0);
						plot(x0 += sx, y0 += sy);
						plot(x1, y1);
						plot(x1 += nx, y1 += ny);
					} else {
						plot(x0 += sx, y0);
						plot(x0, y0 += sy);
						plot(x1 += nx, y1);
						plot(x1, y1 += ny);
					}
					d += incr2;
				}
			}
			if (extras > 0) {
				if (d < 0) {
					plot(x0, y0 += sy);
					if (extras > 1) plot(x0, y0 += sy);
					if (extras > 2) plot(x1, y1 += ny);
				} else
				if (d < c) {
					plot(sx, y0 += sy);
					if (extras > 1) plot(x0 += sx, y0 += sy);
					if (extras > 2) plot(x1, y1 += ny);
				} else {
					plot(x0 += sx, y0 += sy);
					if (extras > 1) plot(x0, y0 += sy);
					if (extras > 2) plot(x1 += nx, y1 += ny);
				}
			}
		} else {
			c = (dx - dy) << 1;
			incr1 = c << 1;
			d =  incr1 + dy;
			for (i = 0; i < length; i++) {
				y0 += sy;
				y1 += ny;
				if (d > 0) {
					plot(x0 += sx, y0);
					plot(x0 += sx, y0 += sy);
					plot(x1 += ny, y1);
					plot(x1 += nx, y1 += ny);
					d += incr1;
				} else {
					if (d < c) {
						plot(x0, y0);
						plot(x0 += sx, y0 += sy);
						plot(x1, y1);
						plot(x1 += nx, y1 += ny);
					} else {
						plot(x0 += sx, y0);
						plot(x0, y0 += sy);
						plot(x1 += nx, y1);
						plot(x1, y1 += ny);
					}
					d += incr2;
				}
			}
			if (extras > 0) {
				if (d > 0) {
					plot(x0 += sx, y0 += sy);
					if (extras > 1) plot(x0 += sx, y0 += sy);
					if (extras > 2) plot(x1 += nx, y1 += ny);
				} else
				if (d < c) {
					plot(x0, y0 += sy);
					if (extras > 1) plot(x0 += sx, y0 += sy);
					if (extras > 2) plot(x1, y1 += ny);
				} else {
					plot(x0 += sx, y0 += sy);
					if (extras > 1) plot(x0, y0 += sy);
					if (extras > 2) {
						if (d > c)
						plot(x1 += nx, y1 += ny);
						else
						plot(x1, y1 += ny);
					}
				}
			}
		}
	}
}
*/

/*
// draw null terminated string at specified column and row
void print_text(byte col, byte row, char *str)
{
	byte i, j;					// counters
	byte *s;					// screen pointer
	char c;					// character
	byte *f;					// font pointer
	byte r;					// repeat
	byte d;					// font byte
	byte m;					// bit mask
	// init screen and font pointers
	row *= FONT_HEIGHT * 2;					// double font height by default
	s = (byte*) (((uint) scan_high[current_screen][row] << 8) | scan_low[current_screen][row]) + col ;
	f = font;
	// for each scanline
	for (j = 0; j < FONT_HEIGHT; j++)
	{
		for (r = 0; r < 2; r++)						// repeat scanline twice (double font height)
		{
			// for each character in string
			i = 0;													// init screen/string offset
			c = str[0];											// get first char in string
			while (c != NULL)							// check for last character
			{
				d = f[c - FONT_FIRST_CHAR];		// get font byte
				m = d ^ 0xff;											// get font mask
				s[i] = (s[i] & m) | (d & *CL); 				// set screen byte
				c = str[++i];											// get next char in string
			}
			s += SCANLINE;									// next screen scanline
		}
		f += FONT_CHARS;						// next font scanline
	}
}
*/

/*
void plot(byte x, byte y, byte c)  // plot color c at coordinates x, y
{
	byte *p;	// pointer to screen byte holding the pixel to be set
	byte i;     // shift needed to place pixel within the byte holding it
	// get pixel index within byte holding it (the remainder of x / 4)
	i = x & 0x3;
	// now shift out the remainder
	x >>= 2;
	// get pointer to byte holding the pixel (this is convoluted in C, but it's good to split the table for asm code)
	p = (byte *) ((scan_high[y] << 8) + scan_low[y]);
	// set the byte holding the pixel with pixel bits shifted to the correct place within the byte holding pixel
	p[x] = (p[x] & pixel_mask[i])    // first clear bits under pixel
		| pixel_value[c][i];	// then set (logical or) with color bits
}
*/

