/*  :ts=8 bk=0
 *
 * viacom.c:	Another display hack based on common real-life experience
 *		with Viacom cable service.  Viacom is a registered tradmark
 *		of Viacom Cablevision (probably).
 *
 * Leo L. Schwab			8706.4		(415)-456-6565
 *
 * (-:  Some people accuse me of being sick.  :-)
 * (-:   This should convince any doubters.   :-)
 */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <hardware/blit.h>

#define MINTERM		((int) (NABC | ANBC  |  NABNC | ANBNC))
#define	PLUSX		100
#define PLUSY		50


extern void	*OpenLibrary(), *OpenScreen(), *OpenWindow(), *GetMsg(),
		*AllocRaster(), *CreatePort(), *FindPort();
extern long	VBeamPos();
extern int	rnd();

struct NewWindow windef = {
	0, 15, 200, 10,
	-1, -1,
	CLOSEWINDOW,
	WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | ACTIVATE,
	NULL, NULL,
	(UBYTE *) "Patching in...",
	NULL, NULL,
	0, 0, 0, 0,
	WBENCHSCREEN
};

struct Screen	*scr;
struct Window	*win;
struct BitMap	noisemap, phonymap;
struct RastPort	nrp;
struct MsgPort	*flagport;
long		nwide, nhigh;
int		wide, high;
void		*IntuitionBase, *GfxBase;

char		*PORTNAME = "Viacom Public Port";


main ()
{
	register struct Screen *wbs;
	register struct BitMap *wbbm;
	register int i;
	int deep, xoff, yoff;
	int ox[8], oy[8];
	void *msg;

	openstuff ();
	rnd ((short) -VBeamPos());

	/*  Glean important information from system structures  */
	wbs = win -> WScreen;
	wide = wbs -> Width;
	high = wbs -> Height;
	wbbm = wbs -> ViewPort.RasInfo -> BitMap;
	deep = wbbm -> Depth;

	/*  Make the bitplane with the noise in it.  */
	nwide = wide + PLUSX;
	nhigh = high + PLUSY;
	InitBitMap (&noisemap, 1L, nwide, nhigh);
	if (!(noisemap.Planes[0] = AllocRaster (nwide, nhigh)))
		die ("Noise bitmap allocation failed.");

	InitRastPort (&nrp);
	nrp.BitMap = &noisemap;

	mknoise (nwide, nhigh);

	/*  Replace the workbench you see with my phony one.  */
	makephony (wide, high, deep);
	wbs -> ViewPort.RasInfo -> BitMap = &phonymap;
	MakeScreen (wbs);
	RethinkDisplay ();
	SetWindowTitles (win, "\273> Viacom <\253", "Viacom Cablevision");

	while (1) {
		if (msg = GetMsg (win -> UserPort)) {
			ReplyMsg (msg);
			break;
		}

		OwnBlitter ();
		for (i=0; i<deep; i++) {
			while (abs ((xoff = rnd (PLUSX)) - ox[i]) < 10)
				;
			while (abs ((yoff = rnd (PLUSY)) - oy[i]) < 10)
				;

			oddblit (wbbm -> Planes[i], phonymap.Planes[i],
				 wide, high,
				 noisemap.Planes[0],
				 (int) nwide, (int) nhigh,
				 xoff, yoff, MINTERM);

			ox[i] = xoff;  oy[i] = yoff;
		}
		DisownBlitter ();
		WaitTOF ();
	}

	/*  Return to normal  */
	wbs -> ViewPort.RasInfo -> BitMap = wbbm;
	MakeScreen (wbs);
	RethinkDisplay ();
	closestuff ();
}

mknoise (wide, high)
long wide, high;
{
	register unsigned int x, i;

	SetRast (&nrp, 0L);
	SetDrMd (&nrp, COMPLEMENT);

	for (x=0; x<wide; x++)
		for (i=0; i<20; i++)
			WritePixel
			 (&nrp, (long) x, (long) rnd ((short) high));
}

abs (x)
int x;
{
	return (x < 0 ? -x : x);
}

makephony (wide, high, deep)
int wide, high, deep;
{
	InitBitMap (&phonymap, (long) deep, (long) wide, (long) high);

	while (deep--)	/*  deep decremented after test  */
		if (!(phonymap.Planes[deep] = AllocRaster
					       ((long) wide, (long) high)))
			die ("Couldn't allocate clone bitmap.");
}

openstuff ()
{
	/*
	 * Running Viacom multiple times at once could really muck things
	 * up, especially if you exit them in the wrong order.  So we do
	 * this so that only one Viacom process is active at any given time.
	 */
	if (FindPort (PORTNAME))
		die ("You are already connected to Viacom.");
	else
		flagport = CreatePort (PORTNAME, NULL);

	initblitdata ();

	if (!(IntuitionBase = OpenLibrary ("intuition.library", 0L)))
		die ("-=RJ=- is on vacation.");

	if (!(GfxBase = OpenLibrary ("graphics.library", 0L)))
		die ("Dale?  Are you there?");

	if (!(win = OpenWindow (&windef)))
		die ("Window painted shut.");
}

closestuff ()
{
	register int i;

	for (i=0; i<phonymap.Depth; i++)
		if (phonymap.Planes[i])
			FreeRaster
			 (phonymap.Planes[i], (long) wide, (long) high);

	if (noisemap.Planes[0])
		FreeRaster (noisemap.Planes[0], nwide, nhigh);

	if (win)		CloseWindow (win);
	if (scr)		CloseScreen (scr);
	if (GfxBase)		CloseLibrary (GfxBase);
	if (IntuitionBase)	CloseLibrary (IntuitionBase);
	if (flagport)		DeletePort (flagport);
}

die (str)
char *str;
{
	puts (str);
	closestuff ();
	exit (20);
}
