/* :ts=8 bk=0
 *
 * oddblit.c:	Custom blitter routine.  Stolen from Tomas Rokicki's LIFE
 *		program and mashed up beyond all recognition.  Nearly all
 *		comments are Tom's.
 *
 * Leo L. Schwab			8706.4
 */

#include <exec/types.h>

/*
 *   This include file includes the defines for all the blitter functions.
 *   It only allows use of the `blit' operations; for area fills or line
 *   drawing, it will need to be extended.
 *
 *   Information gleaned from the Hardware Reference Manual.
 */
#define BLTADD (0xdff040L)

/*
 *   This structure contains everything we need to know.
 *   Do not do a structure copy into this!  Instead, assign
 *   each field.  The last field assigned must be bltsize; that
 *   starts up the blitter.  Also note that all of these are
 *   write only, and you can't read them.
 */
struct bltstruct {
	short con0;
	short con1;
	short afwm;
	short alwm;
	short *csource, *bsource, *asource, *dsource;
	short bltsize;
	short dmy1, dmy2, dmy3;
	short cmod, bmod, amod, dmod;
} *blitter = BLTADD;

/*
 * We need an array which tells what to use for all 256 possible operations.
 */
#define USEA		(0x8)
#define USEB		(0x4)
#define USEC		(0x2)
#define USED		(0x1)

char touse[256];
char fwma[16];
char lwma[16];

/*
 *   Call initblitdata() once on startup before you ever call oddblit.
 */
initblitdata()
{
	register int i;
	register int s;

	for (i=0; i<256; i++) {
		s = USED;
		if ((i >> 4) != (i & 15))
			s += USEA;
		if (((i >> 2) & 51) != (i & 51))
			s += USEB;
		if (((i >> 1) & 85) != (i & 85))
			s += USEC;
		touse[i] = s;
	}
	s = 0xffff;
	for (i=0; i<16; i++) {
		fwma[i] = s;
		s = (s >> 1) & ~0x8000 ;
		lwma[i] = 0xffff - s;
	}
}

/*
 * (Tom's original speech:)
 *   This is the major user interface.  Takes addresses and offsets for
 *   all four locations, a modulo and sizes, and a function.
 *   Assumes the modulos for all sources and destination are the same.
 *   You might want to add some arguments or delete some.
 *
 *   All arguments are in pixels (except the addresses and function.)
 *
 *   Before you call this routine, call OwnBlitter(); after you have
 *   called it as many times as you need, call DisownBlitter().  Remember
 *   that you cannot do any printf's or anything else which requires the
 *   blitter when you own the blitter, so be careful with the debug code.
 *   The machine will lock but will not crash.
 */

/*
 * Leo here.  This is the bit I mashed to pieces.  Using Tom's BlitLab
 * program (wonderful thing), I figured out what it was I wanted to do.
 * So sit back, relax, and enjoy the narrative to follow...
 *
 * It is assumed that src and dest bitmap are identically sized,
 * and that the noise bitmap is larger than both of them.
 * All x,y parameters are in pixels.
 *
 * Note that this does NOT do a general arbitrary rectangle to rectangle
 * logic function.  It's just a quick hack to OR random bits from one
 * bitplane with another, and place the result into a third location.
 */

oddblit (src, dest, sdx, sdy,
	 noise, nx, ny,
	 xoff, yoff, minterm)
short *src, *dest, *noise;
int sdx, sdy, nx, ny, xoff, yoff;
int minterm;
{
	int noisemod;

	/*  Compute width of bitplanes in words  */
	sdx = (sdx + 15) >> 4;
	nx = (nx + 15) >> 4;

	/*  noisemod is in bytes  */
	noisemod = (nx - sdx) * 2;

	/*  Wait for blitter to finish whatever it may be doing  */
	WaitBlit ();

	/*  Start tromping the blitter  */
	blitter -> bsource = src;
	blitter -> dsource = dest;
	blitter -> afwm = blitter -> alwm = 0xffff;

	/*  Compute start address into noise plane  */
	blitter -> asource = noise + yoff * nx + (xoff >> 4);

	/*  Compute desired shift for noise plane  */
	xoff &= 15;

	/*  Comnpute and write control words  */
	blitter -> con0 = (xoff << 12) + (touse[minterm] << 8) + minterm;
	blitter -> con1 = 0;	/*  No shifts on B source or flags  */

	/*  Write out the modulos  */
	blitter -> amod = noisemod;
	blitter -> bmod = 0;	/*  These are sized precisely  */
	blitter -> dmod = 0;

	/*
	 *   This last assignment starts up the blitter.
	 */
	blitter->bltsize = (sdy << 6) + sdx;
}
