/* Trails, by Oren Peli, Copyright (c) 1988 BazboSoft! */

#include <graphics/gels.h>
#include <hardware/cia.h>

void *OpenLibrary();

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;

struct Screen *OpenWorkBench();

struct Screen *scr;

PLANEPTR pln[4];

PLANEPTR AllocRaster();

struct BitMap *bm;

WORD olddepthglob , newdepthglob;

WORD pointer_data0[16 * 2 * 3] = { 0 };
WORD *pointer_data1;
WORD *pointer_data2;

WORD is[16 * 2] = { 0 };

WORD bl[4] = { 0 };

struct RastPort trp;
struct BitMap tbm;

struct VSprite vs;
struct VSprite dummyhead , dummytail;
struct Bob bob;
struct GelsInfo gi;

WORD bob_added = NULL;

main()
{
	REGISTER WORD olddepth , t , i;

	REGISTER struct ViewPort *vp;

	REGISTER struct Preferences prefs;

	pointer_data1 = pointer_data0 + 16 * 2;
	pointer_data2 = pointer_data1 + 16 * 2;

	pln[0] = pln[1] = pln[2] = pln[3] = NULL;

	puts("Trails, by Oren Peli, Copyright (c) 1988 BazboSoft!\nMove the mouse. The left mouse button will clear the screen.\n\nPress CTRL-C to abort (or use 'Break').");

	if (NOT (IntuitionBase = OpenLibrary("intuition.library" , 33L) ) )
		bye();

	if (NOT (GfxBase = OpenLibrary("graphics.library" , 33L) ) )
		bye();

	GetPrefs(&prefs , (LONG) sizeof(struct Preferences) );

	InitBitMap(&tbm , 3L , 32L , 16L);

	InitRastPort(&trp);

	trp.BitMap = &tbm;

	setmem(pointer_data0 , 16 * 2 , 0);
	setmem(pointer_data1 , 16 * 2 , 0);
	setmem(pointer_data2 , 16 * 2 , 0);

	for (i = 0 ; i != 16 ; i++)
	{
		pointer_data0[i * 2] = prefs.PointerMatrix[i * 2];
		pointer_data1[i * 2] = prefs.PointerMatrix[i * 2 + 1];
		pointer_data2[i * 2] = pointer_data0[i * 2] | pointer_data1[i * 2];
	}

	scr = OpenWorkBench();

	bm = scr->ViewPort.RasInfo->BitMap;

	tbm.Planes[0] = (PLANEPTR) pointer_data0;
	tbm.Planes[1] = (PLANEPTR) pointer_data1;
	tbm.Planes[2] = (PLANEPTR) pointer_data2;

	olddepth = bm->Depth;

	if (3 > olddepth)
	{
		if (NOT alloc_planes(olddepth , 3 , scr->Width , scr->Height) )
		{
			puts("Not enough memory!");

			bye();
		}
	}

	newdepthglob = 3;
	olddepthglob = olddepth;

	vp = & scr->ViewPort;

	t = GetRGB4(vp->ColorMap , 16L);
	SetRGB4(vp , 4L , (LONG) t >> 8L , (LONG) ( (t & 0x0f0L) >> 4L) , (LONG) t &
																				0x00fL);

	t = GetRGB4(vp->ColorMap , 17L);
	SetRGB4(vp , 5L , (LONG) t >> 8L , (LONG) ( (t & 0x0f0L) >> 4L) , (LONG) t &
																				0x00fL);

	t = GetRGB4(vp->ColorMap , 18L);
	SetRGB4(vp , 6L , (LONG) t >> 8L , (LONG) ( (t & 0x0f0L) >> 4L) , (LONG) t &
																				0x00fL);

	t = GetRGB4(vp->ColorMap , 19L);
	SetRGB4(vp , 7L , (LONG) t >> 8L , (LONG) ( (t & 0x0f0L) >> 4L) , (LONG) t &
																				0x00fL);

	for (i = 15 ; i >= 0 ; i--)
	{
		ClipBlit(&trp , (LONG) i , 0L , &trp , (LONG) i * 2L , 0L , 1L , 16L , 0xC0L);

		ClipBlit(&trp , (LONG) i , 0L , &trp , (LONG) i * 2L + 1L , 0L , 1L , 16L ,
																				0xC0L);
	}

	InitGels(&dummyhead , &dummytail , &gi);

	scr->RastPort.GelsInfo = &gi;

	vs.Height = 16;
	vs.VSBob = &bob;
	vs.Width = 2;
	vs.Depth = 3;
	vs.ImageData = pointer_data0;
	vs.Flags = OVERLAY;
	vs.X = 0;
	vs.Y = 0;

	bob.BobVSprite = &vs;

	vs.PlaneOnOff = 7;
	vs.PlanePick = 7;

	bob.ImageShadow = is;

	bob.DBuffer = NULL;
	bob.SaveBuffer = NULL;

	bob.Before = NULL;
	bob.After = NULL;

	vs.BorderLine = bl;
	vs.CollMask = is;

	InitMasks(&vs);

	AddBob(&bob , &scr->RastPort);

	bob_added = 1;

	for (;;)
	{
		vs.X = scr->MouseX + prefs.XOffset * 2L + 2L;
		vs.Y = scr->MouseY + prefs.YOffset - 1L;

		SortGList(&scr->RastPort);

		DrawGList(&scr->RastPort , &scr->ViewPort);

		Chk_Abort();

		if (NOT (ciaa.ciapra & 64) )
			puts("");
	}
}

_abort()
{
	if (bob_added)
		RemIBob(&bob , &scr->RastPort , &scr->ViewPort);

	delete_planes(newdepthglob , olddepthglob , scr->Width , scr->Height);

	puts("");

	bye();
}

alloc_planes(olddepth , newdepth , width , height)
register int olddepth , newdepth , width , height;
{
	register int i;

	Forbid();

	for (i = olddepth ; i != newdepth ; i++)
		if (NOT (pln[i] = AllocRaster( (long) width , (long) height) ) )
		{
			Permit();

			return(NULL);
		}

		else
		{
			BltClear(pln[i] , (long) RASSIZE(width , height) , NULL);

			bm->Planes[i] = pln[i];
		}

	bm->Depth = newdepth;

	Permit();

	MakeScreen(scr);

	RethinkDisplay();

	return(1);
}

delete_planes(olddepth , newdepth , width , height)
register int olddepth , newdepth , width , height;
{
	register int i;

	Forbid();

	for (i = newdepth ; i != olddepth ; i++)
	{
		FreeRaster(bm->Planes[i] , (long) width , (long) height);

		bm->Planes[i] = NULL;
	}

	bm->Depth = newdepth;

	Permit();

	MakeScreen(scr);

	RethinkDisplay();

	return(1);
}

bye()
{
	register int i , width = scr->Width , height = scr->Height;

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);

	if (GfxBase)
		CloseLibrary(GfxBase);

	exit(0);
}
