
/*
* Sample, h_fade.java, fade effect with three simples patterns
* For free use, copy, modify.
* By La Trong Hung, latronghung@yahoo.com
* Last modified, 01/2001
* SUMMARY:
*	Create two pixel arrays -> LoadImg()
*	Render and create pixel array that is the source for create main image -> render() <- handlePix(...)
*	Use this array to create main image -> createMainImg()
*/

//===========================================================================================//

import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.net.*;

//===========================================================================================//

public class h_fade extends Applet implements Runnable{

	private Thread th = null;
	private MediaTracker mt;  
	private Image mainImg;
	private Graphics mainG;
	private String hung, link;
	private boolean Init_Complete = false;
	private boolean thSuspended = false; 
	private Image linkImg;			      		// message
	private String mesString;				// Message String
	private int  mouseX, mouseY;				// Mouse position

	private MemoryImageSource memS;
	private int h_Iw, h_Ih;
	private Image img;
	private int m1, m2, m3;
	private final int d1 = 60, d2 = 100, d3 = 40;
	private int pix1[], pix2[], pix[], pixc[];
	private String imgName1, imgName2;
	private int flag = -1;					// Flag to change pixc[]
	private int rr;						// Math.sqrt(h_Iw^2/4 + h_Ih^2/4)
	private int renderFlag;					// Flag to change render pattern

//---------------------------------Initialization------------------------------------------//
   public h_fade(){}

   public void init(){
         						String Bean;
         Bean = getParameter("link");
         	link = (Bean != null) ? Bean : null;
		mesString = (link != null) ? link : "Sample by La Trong Hung";
         Bean = getParameter("hung");
         	hung = (Bean != null) ? Bean : "_self";
         Bean = getParameter("imagename1");
         	imgName1 = (Bean != null) ? Bean : "img1.jpg";
         Bean = getParameter("imagename2");
         	imgName2 = (Bean != null) ? Bean : null;
   }
   private void LoadImg(){
		h_Iw = 1000;
		h_Ih = 1000;
		int h1, h2, w1, w2;
		Image img1, img2 = null;
       		mt = new MediaTracker(this);
       		img1 = getImage(getCodeBase(), imgName1);
           		mt.addImage(img1, 0);
		if(imgName2 != null){
       			img2 = getImage(getCodeBase(), imgName2);
           		mt.addImage(img2, 0);
		}
       		try {
           		mt.waitForAll();
       		}
       		catch(InterruptedException e){};
       		w1 = img1.getWidth(this);
       		h1 = img1.getHeight(this);
		if(imgName2 != null){
       			w2 = img2.getWidth(this);
       			h2 = img2.getHeight(this);
			h_Iw = Math.min(h_Iw, w1); h_Iw = Math.min(h_Iw, w2);
			h_Ih = Math.min(h_Ih, h1); h_Ih = Math.min(h_Ih, h2);
		}
		else{
			h_Iw = w1;
			h_Ih = h1;
		}
       		pix1 = new int[h_Iw*h_Ih];
		grabPix(img1, pix1, h_Iw, h_Ih);
       		pix2 = new int[h_Iw*h_Ih];
		if(imgName2 != null)
			grabPix(img2, pix2, h_Iw, h_Ih);
		else
			createPix2(h_Iw, h_Ih, pix1, pix2);
   }
   private void createPix2(int w, int h, int[] p, int[] p2){
		for(i = 0; i < h*w; i++){
             				r1 = (p[i] >> 16) & 0xFF;
             				g1 = (p[i] >>  8) & 0xFF;
             				b1 = (p[i]      ) & 0xFF;
					int kk = (r1+g1+b1)/3;
					int kkk = kk + 40; if (kkk > 255) kkk = 255;
             				p2[i] = (kk << 16) | (kk << 8) | kkk | 0xFF000000;
		}
   }
   private void grabPix(Image im, int[] pix, int w, int h){
       		PixelGrabber h_PixGrab = new PixelGrabber(im, 0, 0, w, h, pix, 0, w);
       		try {
          		h_PixGrab.grabPixels();
       		}
       		catch (InterruptedException e){
           		System.out.println("grabber error" + e);
           		return;
       		}
       		if ((h_PixGrab.status() & ImageObserver.ABORT) != 0){
           		System.out.println("grabber error");
           		return;
       		}
   }
   private void render(){
	if(renderFlag == 1){
		handlePix1(m1, h_Iw, h_Ih,  pixc, pix);
		m1 += 3;
		if(m1 >= h_Ih){
			m1 = -d1;
			flag = -flag;
			selectCopy();
			renderFlag = 2;
		}
	}
	else if(renderFlag == 2){
		handlePix2(m2, h_Iw, h_Ih,  pixc, pix);
		m2 += 3;
		if(m2 >= h_Iw + h_Ih){
			m2 = -d2;
			flag = -flag;
			selectCopy();
			renderFlag = 3;
		}
	}
	else{
		handlePix3(m3, h_Iw, h_Ih,  pixc, pix);
		m3 += 2;
		if(m3 >= rr){
			m3 = -d3;
			flag = -flag;
			selectCopy();
			renderFlag = 1;
		}
	}

   }
   private void selectCopy(){
	if(flag < 0)
		System.arraycopy(pix2, 0, pixc, 0, pix2.length);
	else
		System.arraycopy(pix1, 0, pixc, 0, pix1.length);
   }
   private void initSetting(){
	 	LoadImg();
		renderFlag = 1;
		pix = new int[h_Iw*h_Ih];
		System.arraycopy(pix1, 0, pix, 0, pix1.length);
		pixc = new int[h_Iw*h_Ih];
		System.arraycopy(pix2, 0, pixc, 0, pix2.length);
		m1 = -d1; m2 = -d2; m3 = -d3;
		rr = (int)(Math.sqrt(h_Iw*h_Iw/4+h_Ih*h_Ih/4));
         	mainImg = createImage(h_Iw, h_Ih);
         	mainG = mainImg.getGraphics();
         	memS = new MemoryImageSource(h_Iw, h_Ih, pix, 0, h_Iw);

	 	mouseX = -1;
	 	mouseY = -1;
	 	linkImg = createMesImg(mesString);
           	Init_Complete = true;
   }
////////////////////////////INSERT VAR
int i, x, y = 0, k = 0;
int r1, g1, b1, r2, g2, b2;
int st, en;
float rate;
//////////////////////////////////////
   private void handlePix1(int m, int w, int h, int[] pc, int[] p){
	k = 0;
	y = m - 3;
	st = (m-3)*w;
	en = (m + d1)*w; if (en > w*h) en = h*w;
	for(i=st; i<en; i++){
			if(i != st && i % w == 0){
				y++; k++;
			}
			if(y >= 0){
				if(i < m*w) p[i] = pc[i];
				else{
             				r1 = (p[i] >> 16) & 0xFF;
             				g1 = (p[i] >>  8) & 0xFF;
             				b1 = (p[i]      ) & 0xFF;
             				r2 = (pc[i] >> 16) & 0xFF;
             				g2 = (pc[i] >>  8) & 0xFF;
             				b2 = (pc[i]      ) & 0xFF;
					rate = (float)k/(float)d1;
             				r1 = (int)((1-rate)*r2+rate*r1); if(r1 > 255) r1 = 255; if(r1 < 0) r1 = 0;
	     				g1 = (int)((1-rate)*g2+rate*g1); if(g1 > 255) g1 = 255; if(g1 < 0) g1 = 0;
	     				b1 = (int)((1-rate)*b2+rate*b1); if(b1 > 255) b1 = 255; if(b1 < 0) b1 = 0;
             				p[i] = (r1 << 16) | (g1 << 8) | b1 | 0xFF000000;
				}
			}
	}
   }
   private void handlePix2(int m, int w, int h, int[] pc, int[] p){
	y = 0;
	for(i=0; i<w*h; i++){
			if(i != 0 && i % w == 0){
				y++;
			}
			x = i - y*w;
			if(x + y > m && x + y <= m + d2){
             				r1 = (p[i] >> 16) & 0xFF;
             				g1 = (p[i] >>  8) & 0xFF;
             				b1 = (p[i]      ) & 0xFF;
             				r2 = (pc[i] >> 16) & 0xFF;
             				g2 = (pc[i] >>  8) & 0xFF;
             				b2 = (pc[i]      ) & 0xFF;
					rate = (float)(x+y-m)/(float)d2;
             				r1 = (int)((1-rate)*r2+rate*r1); if(r1 > 255) r1 = 255; if(r1 < 0) r1 = 0;
	     				g1 = (int)((1-rate)*g2+rate*g1); if(g1 > 255) g1 = 255; if(g1 < 0) g1 = 0;
	     				b1 = (int)((1-rate)*b2+rate*b1); if(b1 > 255) b1 = 255; if(b1 < 0) b1 = 0;
             				p[i] = (r1 << 16) | (g1 << 8) | b1 | 0xFF000000;
			}
	}
   }
///////////////INSERT VAR
int xu, yu, ra;
   private void handlePix3(int m, int w, int h, int[] pc, int[] p){
	y = 0;
	for(i=0; i<w*h; i++){
			if(i != 0 && i % w == 0){
				y++;
			}
			x = i - y*w;
	        	xu = x - h_Iw/2;
	        	yu = y - h_Ih/2;
			ra = (int)(Math.sqrt(xu*xu + yu*yu));
			if(ra > m && ra <= m + d3){
             				r1 = (p[i] >> 16) & 0xFF;
             				g1 = (p[i] >>  8) & 0xFF;
             				b1 = (p[i]      ) & 0xFF;
             				r2 = (pc[i] >> 16) & 0xFF;
             				g2 = (pc[i] >>  8) & 0xFF;
             				b2 = (pc[i]      ) & 0xFF;
					rate = (float)(ra-m)/(float)d3;
             				r1 = (int)((1-rate)*r2+rate*r1); if(r1 > 255) r1 = 255; if(r1 < 0) r1 = 0;
	     				g1 = (int)((1-rate)*g2+rate*g1); if(g1 > 255) g1 = 255; if(g1 < 0) g1 = 0;
	     				b1 = (int)((1-rate)*b2+rate*b1); if(b1 > 255) b1 = 255; if(b1 < 0) b1 = 0;
             				p[i] = (r1 << 16) | (g1 << 8) | b1 | 0xFF000000;
			}
	}
   }
   private void createMainImg(){
		if(Init_Complete == false){
			repaint();
			initSetting();
		}
		render();
		img = createImage(memS);
				mt = new MediaTracker(this);
	 	      		mt.addImage(img, 1);
 		      		try {
 		          		mt.waitForID(1);
 		      		}
 		      		catch(InterruptedException e){};
		mainG.drawImage(img, 0, 0, this);
		if(mouseX >= 0)
			mainG.drawImage(linkImg, mouseX, mouseY-16, this);
   }
//____________________________________State of thread_______________________________________//
   public void start(){
      	if(th == null){
         	th = new Thread(this);
         	th.start();
      	}
   }

   public void stop(){
      	if(th != null){
          	th.stop();
          	th = null;
      	}
   }

   public void destroy(){
        //All destroy
   }

   public void update(Graphics g){
  	    	paint(g);
   }

   public void paint(Graphics g){
	if(Init_Complete == true){
	    	g.drawImage(mainImg, 0, 0, this);
	}
	else{
		g.setColor(Color.red);
		g.drawString("Initializing...", 10, 20);
	}
   }

   public void run(){
       	while(Thread.currentThread() == th){  
           	try {
  	             createMainImg();
                     repaint();
                     Thread.sleep(20);
                     System.gc();
            	} 
            	catch(InterruptedException E) {
                     E.printStackTrace();
            	}
       	}
   }
//____________________________________Applet Information_____________________________________//
   public String getAppletInfo() {
		return "Name: h_fade\r\n" + "Author: La Trong Hung\r\n" + "Created with JDK 1.02";
   }

   public String[][] getParameterInfo()
   {
		String[][] info =
		{
			{ "link", "A String value", "URL to jump" },
			{ "imagename1", "A String value", "Name of Image1" },
			{ "imagename2", "A String value", "Name of Image2 if use" },
		};
		return info;		
   }
//____________________________________Mouse activity_________________________________________//
   public boolean mouseDown(Event evt, int x, int y){
      	if (link != null){
	         try{
        		    URL url = new URL(getDocumentBase(), link);
		            getAppletContext().showDocument(url, hung);
		            if (hung.equals("_self")){
               				stop();
            	 	    }
         	 }
         	 catch (MalformedURLException E){
            		    E.printStackTrace();
         	 }
      	}
      	else{
		 if (thSuspended) th.resume();
		 else  th.suspend();
		 thSuspended = !thSuspended;
      	}
      	return(true);
   }
   public boolean mouseEnter(Event evt, int x, int y){
         	showStatus(mesString);
		mouseX = x;
		mouseY = y;
      		return(true);
   }
   public boolean mouseMove(Event evt, int x, int y){
		mouseX = x;
		mouseY = y;
		return(true);
   }
   public boolean mouseExit(Event evt, int x, int y){
         	showStatus("");
		mouseX = -1;
		mouseY = -1;
      		return(true);
   }
//_____________________________________Message______________________________________________//
	public Image createMesImg(String mes){
		Image linkImage;
		Graphics g;
		int mw;
		int mh = 16;
		mw = 6*mes.length();
		linkImage = createImage(mw, mh);
		g = linkImage.getGraphics();
		g.setColor(new Color(255, 255, 190));
		g.fillRect(0, 0, mw, mh);
		g.setColor(Color.black);
		g.drawRect(0, 0, mw-1, mh-1);
		g.drawString(mes, 4, 12);
		return linkImage;
	}
}
