/*********************************************************************************************/
/*                                                                                           */
/*  Java Image Demo -Plasma                                                                  */
/*  Auth: bkenwright@xbdev.net                                                               */
/*  URL: www.xbdev.net                                                                       */
/*                                                                                           */
/*  Animated CandyBar Rotating                                                               */                                                                                   
/*                                                                                           */
/*********************************************************************************************/

import java.awt.image.*;
import java.awt.*;
import java.applet.*;

import java.awt.Rectangle;


class Colour
{
  public int r,g,b;
}

public class candybar extends Applet implements Runnable
{
   private Thread m_thread        = null;
   public Screen scr;
   public Screen scrB;

   int w;    
   int h;

   public synchronized void update(Graphics g)
   {
      int[] pixels = scr.GetPixels();
      int[] pixelsB = scrB.GetPixels();
      w=scr.GetWidth();    
      h=scr.GetHeight();

      Pattern(pixels, pixelsB, w, h );
      //scr.Render(g);
      scrB.Render(g);

   }// End update(..)


   public void init()
   {
      scr  = new Screen(320,320);
      scrB = new Screen(320,320);
      initPattern();
   }// End init(..)

   Colour[] colours;
   Rectangle crect1;
   Rectangle crect2;
   Rectangle crect3;
   Rectangle crect4;


   void initPattern()
   {
      colours = new Colour[ 256 ];
      
      int i;

      for(int t=0; t<256; t++)
         colours[t] = new Colour();

      /* create palette */
      for (i = 0; i < 128; ++i)
      {
         colours[i].r = i << 1;
         colours[i].g = 0; 
         colours[i].b = 0;
         colours[i + 128].r = 0xFF - (i << 1);
         colours[i + 128].g = 0xFF - (i << 1);
         colours[i + 128].b = 0xFF - (i << 1);
      }// End for loop 

      int w=scr.GetWidth();    
      int h=scr.GetHeight();

      crect1 = new Rectangle(0, 1, w, 127);
      crect2 = new Rectangle(0, 0, w, 127);
      crect3 = new Rectangle(0, 127, w, 1);
      crect4 = new Rectangle(0, (h >> 1) - 64, w, 1);

      int[] pixels = scr.GetPixels();
      w=scr.GetWidth();    
      h=scr.GetHeight();
      PatternSettup(pixels, w, h);

   }//End initPattern()


   void FillRect(int pix[], int width, int height,
                 int x, int y, int w, int h, int col)
   {
      for(int i=y; i <(y+h); i++)
      {
         for(int j=x; j<(x+w); j++)
         {
            pix[ j + i*w ] = col;
         }//End inner for loop
      }// End outer for loop

   }// End FillRect(..)

   int GetR(int pix[], int width, int height,
            int x, int y)
   {
      int col = pix[ x + y*width];
      col = (col>>16)&0xff;
      return col;
   }// End GetR(..)

   int GetG(int pix[], int width, int height,
            int x, int y)
   {
      int col = pix[ x + y*width];
      col = (col>>8)&0xff;
      return col;
   }// End GetG(..)

   int GetB(int pix[], int width, int height,
            int x, int y)
   {
      int col = pix[ x + y*width];
      col = (col)&0xff;
      return col;
   }// End GetB(..)


   void PatternSettup(int pix[], int width, int height)
   {
      
      Rectangle r = new Rectangle(0, 0, width, 16);
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFF0000 );
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFFFFFF) ;
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFF0000) ;
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFFFFFF) ;
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFF0000);
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFFFFFF) ;
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFF0000 );
      r.y += 16;
      FillRect(pix, width, height,    r.x,r.y,r.width,r.height, 0xFFFFFFFF );
   }// End PatternSettup(..)


   void SurfaceCopy(int pix[], int width, int height,
                    Rectangle from, Rectangle to)
   {
      for(int i=to.y, ii=from.y; i<to.height; i++, ii++)
      {
         for(int j=to.x, jj=from.x; j<to.width; j++, jj++)
         {
            pix[j + i*width] = pix[jj + ii*width];
         }//End inner loop
      }//End outer loop
   }// End SurfaceCopy(..)


   void Pattern(int pix[],int pixB[], int width, int height)
   {

      Colour col = new Colour();
      col.r = GetR(pix, width, height, 0, 0 );
      col.g = GetG(pix, width, height, 0, 0 );
      col.b = GetB(pix, width, height, 0, 0 );

      SurfaceCopy( pix, width, height, crect1, crect2 );

      int colx = (0xff<<24) | (col.r<<16) | (col.g<<8) | (col.b);

      FillRect(pix, width, height,    crect3.x, crect3.y, crect3.width, crect3.height, colx );


      int pitch = 0;
 
      for (int i = 0; i < 128; ++i)
      {
          
          col.r = GetR(pix, width, height, width, pitch );
          col.g = GetG(pix, width, height, width, pitch );
          col.b = GetB(pix, width, height, width, pitch );

	  if (i < 64)
	  {
	      col.r &= i << 2;
	      col.b &= i << 2;
	      col.g &= i << 2;
	  }
	  else
	  {
	      col.r &= 0xFF - (i << 2);
	      col.b &= 0xFF - (i << 2);
	      col.g &= 0xFF - (i << 2);	    
	  }

          int colour = (0xff<<24) | (col.r<<16) | (col.g<<8) | (col.b);
          FillRect(pixB, width, height,    crect4.x, crect4.y, crect4.width, crect4.height, colour );
	  crect4.y++;
	  pitch += 1;

       }

       crect4.y = (h >> 1) - 64;
       //System.out.println( "crect4.y : " + crect4.y );

       Rectangle from = new Rectangle(0, 0, w, 126);
       Rectangle to   = new Rectangle(0, 0, w, 126);
       //SurfaceCopy2(pix, width, height,
       //             from, pixB, to );

      // FillRect(pixB, width, height,    to.x, to.y, to.width, to.height, colour );
                    
       
   }// End of Pattern(..)
	
  

   void SurfaceCopy2(int pixFrom[], int width, int height,
                    Rectangle from, int pixTo[], Rectangle to)
   {
      for(int i=to.y, ii=from.y; i<to.height; i++, ii++)
      {
         for(int j=to.x, jj=from.x; j<to.width; j++, jj++)
         {
            pixTo[j + i*width] = pixFrom[jj + ii*width];
         }//End inner loop
      }//End outer loop
   }// End SurfaceCopy(..)


   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 CandyBar 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;
  }
  */
  
  
  


