/*********************************************************************************************/
/*                                                                                           */
/*  Java Image Tutorials - Tut x.x                                                           */
/*  Auth: bkenwright@xbdev.net                                                               */
/*                                                                                           */
/*  Creating Cool Image Effects.                                                             */
/*  This demo isn't the fastest!  But its so the code doesn't get messy...but it shows       */
/*  a great but simple method of generating a cool plasma effect using recursion.            */
/*  All the code for the generation of the plasma effect is all contained in the 'plasma'    */
/*  class - so hopefully you'll be able to pick it appart and see how it works :)            */
/*                                                                                           */
/*********************************************************************************************/

import java.awt.image.*;
import java.awt.*;
import java.applet.*;

import java.util.Random;

public class plasma_recursion extends Applet implements Runnable
{
	private Thread m_thread  = null;
	
  int iC = 0;
	public void  update(Graphics g)
	{		
			plasma p = new plasma();
			p.drawPlasma(g, 320, 320);

			g.setColor(Color.blue);
			g.drawString("Applet Counter: " + iC++ , 20, 25);
	}// End update(..)


  public void run()
	{
			// Remember the starting time
			long thenTime = System.currentTimeMillis() - 2000;
			while (true) 
			{
			    long nowTime = System.currentTimeMillis();
			    long difTime = nowTime - thenTime;
			    
			    // I've set the delay to 0, so its pushing for the MAX fps, you would
			    // set a value in there to limit for example to 25-50 fps refresh rate
			    if( difTime > 2000 )
			    {
			       thenTime = nowTime;
			       // This method provides better updates, instead of filling the
			       // message queue up
			       Graphics g=this.getGraphics();
			       update(g);
			    }
			}// end while loop

	}// End of run() method
	

	public void start()
	{
		if(m_thread == null)
    {
			m_thread = new Thread(this);
			m_thread.setPriority(Thread.MAX_PRIORITY);
			m_thread.start();
		}
		System.out.println( "We are about to start.. \n" );
	}// End of start()

	
}// End of Applet


/*********************************************************************************************/
/*                                                                                           */
/*  Plasma Code                                                                              */
/*                                                                                           */
/*********************************************************************************************/


class plasma
{
   Random generator = new Random();
   
   protected float unit_rand()
   {
      int rmax = 0xff;
	    //float r = (float)(rand()%rmax);
	    //float r = (float)(generator.nextInt( rmax ) ); // isn't supported with java 1.1 only later
	    float r = (float)(generator.nextInt() );         // Have to write our own rand() boundaries
	    r = Math.abs(r);
	    r = r%rmax;
	    r = r/rmax;
	    return r;
   }// End unit_rand()

   protected float Displace(float num)
   {
      int w = 320;
      int h = 320;
	    float max = num / (float)(w + h) * 3;
	    float r = unit_rand();
	    return ((float)r - 0.5f) * max;
   }// End Displace(..)

  protected Color ComputeColor(float c)
	{		
		float Red = 0;
		float Green = 0;
		float Blue = 0;
	
		if (c < 0.5f)
		{
			Red = c * 2;
		}
		else
		{
			Red = (1.0f - c) * 2;
		}
		
		if (c >= 0.3f && c < 0.8f)
		{
			Green = (c - 0.3f) * 2;
		}
		else if (c < 0.3f)
		{
			Green = (0.3f - c) * 2;
		}
		else
		{
			Green = (1.3f - c) * 2;
		}
		
		if (c >= 0.5f)
		{
			Blue = (c - 0.5f) * 2;
		}
		else
		{
			Blue = (0.5f - c) * 2;
		}
		
		// Red, Green and Blue values are between 0 and 255 here
		Color Col = new Color(Red, Green, Blue);
		return Col;
	}// End ComputeColor(..)
	
	protected void DivideGrid(Graphics g, float x, float y, float width, float height, float c1, float c2, float c3, float c4)
	{
		float Edge1, Edge2, Edge3, Edge4, Middle;
		float newWidth = width / 2;
		float newHeight = height / 2;
	
		if (width > 2 || height > 2)
		{	
			Middle = (c1 + c2 + c3 + c4) / 4 + Displace(newWidth + newHeight);	//Randomly displace the midpoint!
			Edge1 = (c1 + c2) / 2;	//Calculate the edges by averaging the two corners of each edge.
			Edge2 = (c2 + c3) / 2;
			Edge3 = (c3 + c4) / 2;
			Edge4 = (c4 + c1) / 2;
				
			//Make sure that the midpoint doesn't accidentally "randomly displaced" past the boundaries!
			if (Middle < 0)
			{
				Middle = 0;
			}
			else if (Middle > 1.0f)
			{
				Middle = 1.0f;
			}
			
			//Do the operation over again for each of the four new grids.			
			DivideGrid(g, x, y, newWidth, newHeight, c1, Edge1, Middle, Edge4);
			DivideGrid(g, x + newWidth, y, newWidth, newHeight, Edge1, c2, Edge2, Middle);
			DivideGrid(g, x + newWidth, y + newHeight, newWidth, newHeight, Middle, Edge2, c3, Edge3);
			DivideGrid(g, x, y + newHeight, newWidth, newHeight, Edge4, Middle, Edge3, c4);
		}
		else	//This is the "base case," where each grid piece is less than the size of a pixel.
		{
			//The four corners of the grid piece will be averaged and drawn as a single pixel.
			float c = (c1 + c2 + c3 + c4) / 4;
			
			Color  Col = ComputeColor(c);
			setpixel(g,  (int)x, (int)y,  Col);
			setpixel(g,  (int)x+1, (int)y, Col);
		}
	
	}// End DivideGrid(..)
	
	public void drawPlasma(Graphics g, int width, int height)
	{
		float c1, c2, c3, c4;
			
		//Assign the four corners of the intial grid random color values
		//These will end up being the colors of the four corners of the applet.		
		c1 = (float)unit_rand();
		c2 = (float)unit_rand();
		c3 = (float)unit_rand();
		c4 = (float)unit_rand();
					
		DivideGrid(g, 0, 0, width , height , c1, c2, c3, c4);
	}// End drawPlasma(..)
	
	protected void setpixel(Graphics g,  int x, int y, Color Col )
	{
	   g.setColor( Col );
		 g.drawRect(x, y, 1, 1);	   //Java doesn't have a function to draw a single pixel, so
												         //a 1 by 1 rectangle is used.
	}// End setpixel(..)

}//End plasma class



