/*

Java Graphics Demos: 

by Orion Lawlor, 12/1998

olawlor@acm.org



This code is totally free, and

should be considered in the public domain.

Use and modify it at will.

*/

import java.awt.*;

import java.awt.image.*;

//import ColorMap;

//import ByteTable;



class Spark

{

	public int x,y;//Integer coordinates of spark

	public byte color;//Index of spark color

	

	double locx,locy;//Coordinates of Spark

	double vx,vy;//Velocity of ball

	

	//Return a random number on [min,max)*/

	double rand(double min,double max)

		{return min+Math.random()*(max-min-0.0000001);}

	

	public Spark() {}

	public Spark(double Nx,double Ny,double Nvx,double Nvy,byte Ncolor)

	{

	//Init variables

		locx=Nx;

		locy=Ny;

		vx=Nvx;

		vy=Nvy;

		color=Ncolor;

	}

	

	public void advance(int screenW,int screenH)

	{
		locx+=vx;locy+=vy;//Move with given velocity

		//Check for border bounce

		double bounceDecay=0.6;

		if (locx<0) {locx-=vx;vx*=-bounceDecay;}

		if (locx>=screenW) {locx-=vx;vx*=-bounceDecay;}

		if (locy<0) {locy-=vy;vy*=-bounceDecay;}

		if (locy>=screenH) {locy-=vy;vy*=-bounceDecay;}

		vy+=1.0;//Accellerate downward (slightly).

		x=(int)locx;y=(int)locy;

	}

}



class Sparker extends Spark

{

	int time=0;

	Spark sparks[];

	int newSpark=0;

	int nSparks=0;

	int maxSparks=45;

	public Sparker(int screenW,int screenH)

	{

		locx=rand(0,screenW);

		locy=rand(0,screenH);

		vy=rand(-screenW/64,screenW/64);

		vx=rand(-screenH/64,screenH/64);

		color=(byte)(int)rand(2,255);

		sparks=new Spark[maxSparks];

		time=(int)rand(0,5000);

	}



	public void eraseOld(int screenW,int screenH,byte pix[])

	{

		int i;

		for (i=0;i<nSparks;i++)

			pix[screenW*sparks[i].y+sparks[i].x]=0;

	}



	public void setDest(double destx,double desty)

	{

		double accx=destx-locx;

		double accy=desty-locy;

		double mag=Math.sqrt(accx*accx+accy*accy);

		double accScale=2.00/mag;

		double velDecay=0.98;

		//Decay current velocity (Air drag)

		vx*=velDecay;

		vy*=velDecay;

		//Accellerate toward destination.

		vx+=accx*accScale;

		vy+=accy*accScale;

	}

	

	void newSpark(double dir,double vel)

	{

		double nvx=vx+vel*Math.cos(dir);

		double nvy=vy+vel*Math.sin(dir);

		sparks[newSpark]=new Spark(locx,locy,nvx,nvy,color);

		

		if (nSparks<maxSparks) 

			nSparks++;//Make room for new spark.

		newSpark++;//Prepare spot for next spark.

		if (newSpark>=maxSparks)

			newSpark=0;//Wrap new spark around.

		

	}

	

	public void drawNew(int screenW,int screenH,byte pix[])

	{

		//Advance ourselves

		super.advance(screenW,screenH);

		

		//Create three spark streams

		double dir=Math.atan2(-vy,-vx);

		double vel=0.5;

		newSpark(dir-0.5,vel+0.2);

		newSpark(dir    ,vel-0.1);

		newSpark(dir+0.5,vel+0.3);

		

		//Advance and draw new sparks

		int i;

		for (i=0;i<nSparks;i++)

		{

			sparks[i].advance(screenW,screenH);

			pix[screenW*sparks[i].y+sparks[i].x]=sparks[i].color;

		}

		

		time++;

	}

}



class Demo 

{

	int w,h;

	Sparker sparkers[];

	int num=12;

	public void init(ColorMap cm,byte pix[],int Nw,int Nh)

	{

		//Broilerplate

		int x,y;

		w=Nw;h=Nh;

		int dex[]  ={   0,  1,  2, 80,170,255},

			red[]  ={   0,255,  0,  0,255,  0},

			green[]={   0,255,  0,255,  0,  0},

			blue[] ={   0,255,255,  0,  0,255};

		cm.addBreaks(dex,red,green,blue);

		

		//Allocate and initialize our array of Sparkers.

		int i;

		sparkers=new Sparker[num];

		for (i=0;i<num;i++)

			sparkers[i]=new Sparker(w,h);

	}

	public boolean handleAction(Event ev,Object obj) {return false;}

	int time=0;

	int dotx=0,doty=0;

	public void drawDot(byte pix[],byte dotColor)

	{

		//Bounds check

		if (dotx<0||dotx>w-2) return;

		if (doty<0||doty>h-2) return;

		//Draw 4 pixels

		pix[(doty  )*w+(dotx  )]=dotColor;

		pix[(doty+1)*w+(dotx  )]=dotColor;

		pix[(doty  )*w+(dotx+1)]=dotColor;

		pix[(doty+1)*w+(dotx+1)]=dotColor;

	}

	public void fillBuffer(ColorMap cm,byte pix[])

	{
		int i;

		//Erase old sparks

		for (i=0;i<num;i++)

			sparkers[i].eraseOld(w,h,pix);

		

		drawDot(pix,(byte)0);//Erase old dot

		dotx=(int)(w/2+w/2*(0.6*Math.cos(time/10.0)+0.3*Math.cos(time/5.0)));

		doty=(int)(h/2+h*0.3*(Math.cos(time/13.12)));

		drawDot(pix,(byte)1);//Draw new dot

		time++;

		

		//Advance and draw new sparks

		for (i=0;i<num;i++)

		{

			sparkers[i].setDest(dotx,doty);

			sparkers[i].drawNew(w,h,pix);

		}

	}

}

