/*********************************************************************************************/
/*                                                                                           */
/*  Java Image Demo -Plasma                                                                  */
/*  Auth: bkenwright@xbdev.net                                                               */
/*  URL: www.xbdev.net                                                                       */
/*                                                                                           */
/*  Plasma                                                                                   */                                                                                   
/*                                                                                           */
/*********************************************************************************************/

import java.awt.image.*;
import java.awt.*;
import java.applet.*;



class Colour
{
  public int r,g,b;
}

public class plasma extends Applet implements Runnable
{
   private Thread m_thread        = null;
   public Screen scr;

   public synchronized void update(Graphics g)
   {
      int[] pixels = scr.GetPixels();
      int w=scr.GetWidth();    
      int h=scr.GetHeight();

      Pattern(pixels, w, h );
      scr.Render(g);
   }// End update(..)


   public void init()
   {
      scr = new Screen(320,320);
      initPattern();
   }// End init(..)

   Colour[] colours;

   int pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0, tpos1, tpos2, tpos3, tpos4;
   int[] aSin;

   void initPattern()
   {
      colours = new Colour[ 256 ];
      aSin = new int[512];
      
      int i;
      float rad;
 
      /*create sin lookup table */
      for (i = 0; i < 512; i++)
      {
         rad =  ((float)i * 0.703125f) * 0.0174532f;     /* 360 / 512 * degree to rad, 360 degrees spread over */
                                                         /*512 values to be able to use AND 512-1 instead of using modulo 360*/
         aSin[i] = (int)(Math.sin(rad) * 1024);          /*using fixed point math with 1024 as base*/
      }// End for loop

      for(int t=0; t<256; t++)
         colours[t] = new Colour();

      /* create palette */
      for (i = 0; i < 64; ++i)
      {
         colours[i].r = i << 2;
         colours[i].g = 255 - ((i << 2) + 1); 
         colours[i+64].r = 255;
         colours[i+64].g = (i << 2) + 1;
         colours[i+128].r = 255 - ((i << 2) + 1);
         colours[i+128].g = 255 - ((i << 2) + 1);
         colours[i+192].g = (i << 2) + 1; 
       }// End for loop 

   }//End initPattern()



   void Pattern(int pix[], int width, int height)
   {
      int i, j;
      float temp;
      int index;
      int x; 
       
      /* draw plasma */

      tpos4 = pos4;
      tpos3 = pos3;

      int[] image = pix;
      int cc=0;
      
      for (i = 0; i < height; ++i)
      {
	  tpos1 = pos1 + 5;
	  tpos2 = pos2 + 3;
	  
	  tpos3 &= 511;
	  tpos4 &= 511;
	  
	  for (j = 0; j < width; ++j)
	  {
	      //tpos1 &= 511;
	      //tpos2 &= 511;

              tpos1 = tpos1 % 511;
              tpos2 = tpos2 % 511;
              tpos3 = tpos3 % 511;
              tpos4 = tpos4 % 511;
	      
	      x = aSin[tpos1] + aSin[tpos2] + aSin[tpos3] + aSin[tpos4]; /*actual plasma calculation*/
	      
	      index = 128 + (x >> 4); /*fixed point multiplication but optimized so basically it says (x * (64 * 1024) / (1024 * 1024)), x is already multiplied by 1024*/

              index = Math.abs(index);
              index = index % 255;
            
              int r = colours[index].r;
	      int g = colours[index].g;
	      int b = colours[index].b;
              int col = (0xff<<24)|(r<<16)|(g<<8)|(b);
              if( cc > (width*height) ) cc = 0;
              image[cc] = col;
	      cc++;
	      
	      tpos1 += 5; 
	      tpos2 += 3; 
          }
	  
          tpos4 += 3;
          tpos3 += 1;
      }

      /* move plasma */
      pos1 +=9;
      pos3 +=8;

   }// End Pattern(..)


	
  
   public void run()
   {
	    
      // Remember the starting time
      long thenTime = System.currentTimeMillis();
      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 > 10 )
	 {
            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( "Starting Plasma Graphics Demo\n" );
   }// End of start()
	
}// End of Applet





/*********************************************************************************************/
/*                                                                                           */
/*  class Screen                                                                             */
/*  Well its the fastest method to plot pixels using MemoryImageSource...and to access your  */
/*  array of pixel data directly...but it sure makes your setup applet code look complicated */
/*  and hides the real reason!  So I've done a sort of back buffer screen class, which we    */
/*  can use to render pixels fastly....for our cool effects...and its all in there...settup  */
/*  and rendering.                                                                           */
/*                                                                                           */
/*********************************************************************************************/
// Few tiny comments
// We need to extend from Applet so we can use, two api's.  createImage(..) and drawImage(..)

class Screen extends Applet
{
   Image m_image;
   int m_pixels[];
   
   int m_width=0;
   int m_height=0;

   MemoryImageSource m_p; 
   public Screen(int width, int height)
   {
     m_pixels = new int[width*height];
     m_width = width;
     m_height = height;
     // Init MemoryImageSource - pixels will be in 32bit ARGB format
		 DirectColorModel dcm=new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
     m_p = new MemoryImageSource(/*width*/m_width,/*height*/m_height,dcm,m_pixels,0,/*width*/m_width);
     m_p.setAnimated(true);
     m_p.setFullBufferUpdates(true);
     m_image = createImage(m_p);
   }// End CScreen(..) constuctor

   public void Render(Graphics g)
   {
      m_p.newPixels(0,0,/*width*/m_width,/*height*/m_height);
      g.drawImage(m_image,0,0, this);
   }// End Render(..)
   
   public int[] GetPixels()
   {
      return m_pixels;
   }// End GetPixels()
   
   
   public int GetWidth() { return m_width; };
   public int GetHeight(){ return m_height; };

}// End Screen(..)


  // Overwrite imageUpdate
  /*
  public boolean imageUpdate(Image image, int i1, int j1, int k, int i2, int j2) {
    return true;
  }
  */
  
  
  

