/*
 *  Copyright (c) 1994 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 <dos/dos.h>

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

#include "/Garshnelib/Garshnelib_protos.h"
#include "/Garshnelib/Garshnelib_pragmas.h"

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

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

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

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 Screen *Scr, LONG ExtendPal )
{
	LONG l, c, i, z = 0, step, nextStep, l1, l2, c1, c2, RetVal = OK;
	struct RastPort *R = &( Scr->RastPort );
	
	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 );
			}
			if(!( ++z % 4 ))
			{
				RainbowPalette( Scr, ColorTable, 1, ExtendPal );
				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;
	struct Window *Wnd;
	LONG i, RetVal = OK;
	
	if( PlasmaWnd )
		pP = &nP;
	else
		pP = ( struct ModulePrefs * )Prefs;

	Scr = OpenScreenTags( NULL, SA_Depth, pP->Depth,SA_DisplayID, pP->Mode,
						 SA_Overscan, OSCAN_STANDARD, 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 )
		{
			ColorTable = RainbowPalette( Scr, 0L, 1, pP->ExtendPal );
			Wnd = BlankMousePointer( Scr );
			
			while( RetVal == OK )
			{
				ScreenToFront( Scr );
				SetRast(&( Scr->RastPort ), 0L );
				RetVal = grow( Scr, pP->ExtendPal );
				
				for( i = 0; ( i < Wid * Hei / 100 )&&( RetVal == OK ); i++ )
				{
					WaitTOF();
					if(!( i % 4 ))
					{
						RainbowPalette( Scr, ColorTable, 1, pP->ExtendPal );
						RetVal = ContinueBlanking();
					}
				}
			}
			
			RainbowPalette( NULL, ColorTable, 1, pP->ExtendPal );
			UnblankMousePointer( Wnd );

			FreeCells( Cell );
		}
		else
			RetVal = FAILED;

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