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

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

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

#include "Plasma.h"
#include "/main.h"
#include "//defs.h"

struct ModulePrefs
{
	LONG Mode;
	LONG Depth;
	LONG LimDimen;
};

extern struct ModulePrefs nP;
LONG Range[] = { 63, 31, 15, 7, 7, 3, 2, 2 }, Hei, Wid, Minor, Offx, Offy, **Cell, Cl, Dimen;

#define BLANKMOUSE
#define RAINBOWPALETTE
#include "/utility.c"

void set( LONG l, LONG c, LONG size, LONG value, struct RastPort *R )
{
	LONG rang;
	
	rang = Range[size];
	value = ( value + RangeRand( rang ) - ( rang + 1 ) / 2 ) % Cl;
	Cell[c][l] = value;
	if( value )
		SetAPen( R, value );
	else
		SetAPen( R, 1 );
	if(( l < Hei )&&( c < Wid ))
		WritePixel( R, c + Offx, l + Offy );
}

LONG grow( struct RastPort *R )
{
	LONG l, c, i, step, nextStep, l1, l2, c1, c2, RetVal = OK;
	
	step = 256;
	for( i = 0; i < 8; i++ )
	{
		nextStep = step / 2;
		for( l = 0; ( l < Minor )&&( RetVal == OK ); l += step )
		{
			l1 = ( l + nextStep ) % Minor;
			l2 = ( l + step ) % Minor;
			for( c = 0; c < Minor; c += step )
			{
				c1 = ( c + nextStep ) % Minor;
				c2 = ( c + step ) % Minor;
				set( l, c1, i, ( Cell[l][c] + Cell[l][c2] + 1 )/2, R );
				set( l1, c, i, ( Cell[l][c] + Cell[l2][c] + 1 )/2, R );
				set( l1, c1, i, ( Cell[l][c] + Cell[l][c2] + Cell[l2][c] + Cell[l2][c2] + 2 )/4,
					R );
			}
			RetVal = ContinueBlanking();
		}
		step = nextStep;
	}

	return RetVal;
}

LONG **FreeCells( LONG **Cells )
{
	LONG i;
	
	if( Cells )
		for( i = 0; i < Minor; i++ )
			if( Cells[i] )
				FreeVec( Cells[i] );
	
	return 0L;
}

LONG **AllocCells( LONG InitColor )
{
	LONG i, j, failed = 0;
	LONG **Cell;
	
	if( Cell = AllocVec( Minor * sizeof( LONG * ), MEMF_CLEAR ))
	{
		for( i = 0; i < Minor; i ++ )
		{
			if(!( Cell[i] = AllocVec( Minor * sizeof( LONG ), MEMF_CLEAR )))
				failed = 1;
			else
				for( j = 0; j < Minor; j++ )
					Cell[i][j] = InitColor;
		}
	}

	if( !failed )
		return Cell;

	return FreeCells( Cell );
}

LONG Blank( VOID *Prefs )
{
	struct ModulePrefs *pP;
	struct Screen *Scr;
	LONG i, RetVal = OK;
	
	if( PlasmaWnd )
		pP = &nP;
	else
		pP = ( struct ModulePrefs * )Prefs;

	Scr = OpenScreenTags( NULL, SA_Depth, pP->Depth, SA_Overscan, OSCAN_STANDARD, SA_DisplayID,
						 pP->Mode, SA_Quiet, TRUE, SA_Behind, TRUE, TAG_DONE );

	if( Scr )
	{
		Cl = 1L << pP->Depth - 1;
		Wid = Scr->Width;
		Hei = Scr->Height;

		if( pP->LimDimen )
		{
			Minor = Hei;
			if( Wid > Hei )
				Offx = ( Wid - Hei )/ 2;
			else
				Offx = 0L;
			Offy = 0L;
		}
		else
		{
			Minor = Wid;
			Offx = 0L;
			if( Hei > Wid )
				Offy = ( Hei - Wid )/ 2;
			else
				Offy = 0;
		}
		
		Cell = AllocCells(( LONG )RangeRand( 256 ));

		if( Cell )
		{
			RainbowPalette( Scr, 1 );
			BlankMousePointer( Scr );
			
			while( RetVal == OK )
			{
				ScreenToFront( Scr );
				SetRast(&( Scr->RastPort ), 0L );
				RetVal = grow(&( Scr->RastPort ));
				
				for( i = 0; ( i < Wid * Hei / 100 )&&( RetVal == OK ); i++ )
				{
					WaitTOF();
					RainbowPalette( Scr, 1 );
					RetVal = ContinueBlanking();
				}
			}
			
			RainbowPalette( NULL, 1 );
			UnblankMousePointer();

			FreeCells( Cell );
		}
		else
			RetVal = FAILED;

		CloseScreen( Scr );
	}
	else
		RetVal = FAILED;
	
	return RetVal;
}
