/* Ripple by Troels Walsted Hansen <troels@stud.cs.uit.no>, based on 
** xripple by Carsten «Rasterman» Haitzler <s2154962@cse.unw.edu.au>.
**
** Source included for your enjoyment, feel free to modify at will.
*/

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <math.h>

#ifndef PID2
#define PID2 1.57079632679489661923
#endif

#ifndef __AMIGADATE__
#define __AMIGADATE__ "(7.11.97)"
#endif

/* gcc has problems with inlining calls to library functions which take 
   a lot of arguments in registers, therefore we use the amiga.lib stub 
   function instead  */

#ifdef __GNUC__
#undef BltBitMap 
#endif

#define TEMPLATE "HEIGHT/N,WAITTOF/S,NOWAIT/S,QUIET/S,USAGE/S"
enum { A_HEIGHT, A_WAITTOF, A_NOWAIT, A_QUIET, A_USAGE, A_MAX};

static const char *version = "$VER: Ripple 1.0 " __AMIGADATE__;

int main(int argc, char **argv)
{
	int retval = RETURN_FAIL;
	STRPTR error = NULL;

	struct RDArgs *rd;
	LONG args[A_MAX] = {0};

	ULONG frames = 0, ticks;
	struct DateStamp start_ds, end_ds;

	struct Screen *s = NULL;
	struct Window *w = NULL;
	struct BitMap *double_bm = NULL, *single_bm = NULL;
	int screen_h, screen_w, screen_d, water_h;

	int y, yy, off, yoff, i = 0;
	double a, incv = 0, inch = 0, aa, p;

	/* argument handling */

	rd = ReadArgs(TEMPLATE, args, NULL);
	if(!rd)
	{
		error = "Error in arguments";
		goto done;
	}

	if(!args[A_QUIET])
	{
		Printf("%s by Troels Walsted Hansen <troels@stud.cs.uit.no>\n"
		       "based on xripple by Carsten «Rasterman» Haitzler <s2154962@cse.unw.edu.au>\n",
		       version+6);
	}

	if(args[A_USAGE])
	{
		error = "Usage: Ripple [<height>] [WAITTOF] [NOWAIT] [QUIET] [USAGE]\n"
		        "Copyright © 1997 Ultima Thule Software";
		retval = RETURN_OK;
		goto done;
	}

	/* initialization */

	s = LockPubScreen(NULL);
	if(!s)
	{
		error = "Couldn't lock default public screen";
		goto done;
	}

	screen_h = s->Height;
	screen_w = s->Width;
	screen_d = GetBitMapAttr(s->RastPort.BitMap, BMA_DEPTH);
	water_h  = args[A_HEIGHT] ? *(int *)args[A_HEIGHT] : 64;
	if(!water_h || water_h > 32767) water_h = 64;

	w = OpenWindowTags(NULL, WA_Left,        0,
	                         WA_Top,         screen_h - water_h,
	                         WA_Height,      water_h,
	                         WA_Width,       screen_w,
	                         WA_SizeGadget,  FALSE, 
	                         WA_DragBar,     FALSE, 
	                         WA_CloseGadget, FALSE, 
	                         WA_Borderless,  TRUE, 
	                         WA_RMBTrap,     TRUE,
	                         WA_PubScreen,   s,
	                         TAG_DONE);
	if(!w)
	{
		error = "Couldn't open window";
		goto done;
	}

	double_bm = AllocBitMap(screen_w, water_h * 2, screen_d, BMF_CLEAR | BMF_MINPLANES, s->RastPort.BitMap);
	if(!double_bm)
	{
		error = "Couldn't allocate double height bitmap";
		goto done;
	}

	single_bm = AllocBitMap(screen_w, water_h, screen_d, BMF_CLEAR | BMF_MINPLANES, s->RastPort.BitMap);
	if(!single_bm)
	{
		error = "Couldn't allocate single height bitmap";
		goto done;
	}

	DateStamp(&start_ds);

	/* creating the ripple effect */

	for(;;)
	{
		BltBitMap(s->RastPort.BitMap, 0, (screen_h-(water_h*3))+i, double_bm, 0, i, screen_w, 1, 0xC0, 0xFF, NULL);

		i=(i+1)%(water_h*2);

		incv+=0.09;
		if(incv > (PID2 * 4)) incv=0;

		inch+=0.06;
		if(inch > (PID2 * 4)) inch=0;

		for (y = 0; y < water_h; y++)
		{
			p=(((double)(water_h-y))/((double)water_h));
			a=p*p*48+incv;

			yoff=y+(int)(sin(a)*7)+1;
			yy=(water_h*2)-yoff;

			aa=p*p*64+inch;
			off=(int)(sin(aa)*10*(1-p));

			if(yy > 0 && yy < water_h*2)
			{
				if(off > 0)
					BltBitMap(double_bm, 0, yy, single_bm, off, y, screen_w - off, 1, 0xC0, 0xFF, NULL);
				else
					BltBitMap(double_bm, -off, yy, single_bm, 0, y, screen_w + off, 1, 0xC0, 0xFF, NULL);
			}
		}

		BltBitMapRastPort(single_bm, 0, 0, w->RPort, 0, 0, screen_w, water_h, 0xC0);
		frames++;

		if(!args[A_NOWAIT])
		{
			if(args[A_WAITTOF]) WaitTOF();
			else WaitBOVP(&s->ViewPort);
		}

		if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) break;
	}

	DateStamp(&end_ds);

	ticks = (end_ds.ds_Days-start_ds.ds_Days) * 86400*TICKS_PER_SECOND
			+(end_ds.ds_Minute-start_ds.ds_Minute) * 60*TICKS_PER_SECOND
			+(end_ds.ds_Tick-start_ds.ds_Tick);

	if(!args[A_QUIET]) Printf("Frames per second: %ld\n", (TICKS_PER_SECOND * frames) / ticks+1);

	retval = RETURN_OK;

done:
	if(error)     Printf("%s\n", error);

	if(single_bm) FreeBitMap(single_bm);
	if(double_bm) FreeBitMap(double_bm);
	if(w)         CloseWindow(w);
	if(s)         UnlockPubScreen(NULL, s);
	if(rd)        FreeArgs(rd);

	return(retval);
}
