/*
 *	Copyright (c) 1993 Michael D. Bayne.
 *	All rights reserved.
 *
 *	Please see the documentation accompanying the distribution for distribution and disclaimer information.
 */

#include <exec/types.h>
#include <exec/memory.h>

#include <intuition/intuition.h>
#include <intuition/screens.h>

#include <dos/dos.h>

#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/copper.h>
#include <graphics/videocontrol.h>
#include <hardware/custom.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/alib_protos.h>
#include <clib/utility_protos.h>

#include "Moiré.h"
#include "/defs.h"
#include "/utility.h"

struct mPrefObject {
	LONG xSpeed, ySpeed, Trail, numLines, Cycle;
};

extern	struct	mPrefObject	nP;
extern		ULONG		Depth, Mode;
extern		UBYTE		*prefData;

VOID blank( VOID )
{
	struct	mPrefObject	*mP;
	struct	Screen		*MoireScr;
	struct 	RastPort	*rp;

	ULONG	numCols, i, j, k, n, Trail, xSpeed, ySpeed;
	WORD	Wid, Hei, **cx, **cy, *dx, *dy, nl;

	if( MoireWnd ) mP = &nP;
	else mP = ( struct mPrefObject * )prefData;

	xSpeed = mP->xSpeed;
	ySpeed = mP->ySpeed;
	nl = mP->numLines;
	Trail = mP->Trail;

	if(!( cx = AllocVec( nl * sizeof( WORD * ), MEMF_CLEAR ))) goto exit;
	if(!( cy = AllocVec( nl * sizeof( WORD * ), MEMF_CLEAR ))) goto exit;
	if(!( dx = AllocVec( nl * sizeof( WORD ), MEMF_CLEAR ))) goto exit;
	if(!( dy = AllocVec( nl * sizeof( WORD ), MEMF_CLEAR ))) goto exit;

	if(!( MoireScr = OpenScreenTags( 0l, SA_DisplayID, Mode, SA_Depth, Depth, SA_Quiet, TRUE, SA_Behind, TRUE,
		SA_Overscan, OSCAN_STANDARD, TAG_DONE ))) goto exit;

	rp = &( MoireScr->RastPort );
	Wid = MoireScr->Width;
	Hei = MoireScr->Height;

   	numCols = (( 1 << rp->BitMap->Depth )-1)%3 ? ( 1 << rp->BitMap->Depth )-1 : ( 1 << rp->BitMap->Depth );

	if( numCols == 1 ) numCols = 2;

	for( k = 0; k < nl; k++ ) {
		if(!( cx[k] = AllocVec( Trail * sizeof( UWORD ), MEMF_CLEAR ))) goto exit;
		if(!( cy[k] = AllocVec( Trail * sizeof( UWORD ), MEMF_CLEAR ))) goto exit;
	}

	SetRGB4( &(MoireScr->ViewPort), 0, 0, 0, 0 );

	switch( mP->Cycle ) {
	case 0:
		RainbowPalette( MoireScr );
		break;
	case 1:
		SetRGB4( &(MoireScr->ViewPort), 1, RangeRand( 14 ) + 1, RangeRand( 14 ) + 1, RangeRand( 14 ) + 1 );
		break;
        case 2:
		SetRGB4( &(MoireScr->ViewPort), 1, 15, 15, 15 );
		break;
	case 3:
		setCopperList( Hei, 1, &( MoireScr->ViewPort ));
		break;
	}
		
	for( k = 0; k < nl; k++ ) {
		cx[k][1] = RangeRand( Wid - 2 ) + 1;
		cy[k][1]= RangeRand( Hei - 2 ) + 1;
		dx[k] = RangeRand( xSpeed ) + 1;
		dy[k] = RangeRand( ySpeed ) + 1;
	}
	i = 0; j = 0;

	BlankMousePointer();
	ScreenToFront( MoireScr );

	while(!(SetSignal(0,0) & SIGBREAKF_CTRL_C )) {

		WaitTOF();

		i = (i+1) % Trail;
		n = (i+1) % Trail;
		j = (j+1) % 255;

		if( !mP->Cycle ) SetAPen( rp, (j*(numCols-1))/255+1 );
		else SetAPen( rp, 1 );

		for( k = 0; k < nl; k++ ) {
			if( cx[k][i] >= Wid ) {
				dx[k] = -1 * RangeRand( xSpeed ) - 1;
				cx[k][i] = Wid-1;
			} else if( cx[k][i] < 0 ) {
				dx[k] = RangeRand( xSpeed ) + 1;
				cx[k][i] = 0;
			}
			if( cy[k][i] >= Hei ) {
				dy[k] = -1 * RangeRand( ySpeed ) - 1;
				cy[k][i] = Hei-1;
			} else if( cy[k][i] < 0 ) {
				dy[k] = RangeRand( ySpeed ) + 1;
				cy[k][i] = 0;
			}
		}

		Move( rp, cx[0][i], cy[0][i] );
		for( k = 1; k < nl; k++ ) Draw( rp, cx[k][i], cy[k][i] );
		if( nl > 2 ) Draw( rp, cx[0][i], cy[0][i] );

		SetAPen( rp, 0 );

		Move( rp, cx[0][n], cy[0][n] );
		for( k = 1; k < nl; k++ ) Draw( rp, cx[k][n], cy[k][n] );
		if( nl > 2 ) Draw( rp, cx[0][n], cy[0][n] );

		for( k = 0; k < nl; k++ ) {
			cx[k][n] = cx[k][i] + dx[k];
			cy[k][n] = cy[k][i] + dy[k];
		}
	}

exit:
	SetSignal( 0L, SIGBREAKF_CTRL_C );

	if( cx ) {
		for( k = 0; k < nl; k++ ) if( cx[k] ) FreeVec( cx[k] );
		FreeVec( cx );
	}
	if( cy ) {
		for( k = 0; k < nl; k++ ) if( cy[k] ) FreeVec( cy[k] );
		FreeVec( cy );
	}
	if( dx ) FreeVec( dx );
	if( dy ) FreeVec( dy );

	if(!( mP->Cycle )) RainbowPalette( NULL );
	UnblankMousePointer();
	if( MoireScr ) CloseScreen( MoireScr );
}
