import java.applet.Applet;
import java.awt.image.*;
import java.awt.*;
import java.net.*;
import java.io.*;

class Normal
{
  int width, height;
  float data[];

public Normal() 
  {
  }

public void read(InputStream in)
  {
    width=60;
    height=80;
    data=new float[width*height*3];
    DataInputStream din=new DataInputStream(in);
    try {
      byte ch=0;
      while (ch!=12) { ch=din.readByte(); }
      din.readByte();
      for (int i=0; i<width*height*3; i++)
	data[i]=din.readFloat();
    } catch (Exception e) { System.err.println("normals: " + e); }
  }

public MemoryImageSource getImageSource(IndexColorModel cm, double x, double y)
  {
    double z=x*x+y*y;
    if (z>=1.0) {
      x/=Math.sqrt(z);
      y/=Math.sqrt(z);
      z=0; 
    } else z=Math.sqrt(1.0-z);
    int yoff=width*height;
    int zoff=2*width*height;
    byte buf[]=new byte[width*height];
    for (int i=0; i<width*height; i++) {
      double tot=x*data[i]+y*data[i+yoff]+z*data[i+zoff];
      if (tot<0) tot=0;
      if (tot>255) tot=255;
      buf[i]=(byte)tot;
    }
    return new MemoryImageSource(width,height,cm,buf,0,width);
  }
}

public class Light extends Applet
{
  Normal norm;
  Image img;
  static IndexColorModel cm;

  static {
    byte red[]=new byte[256];
    byte green[]=new byte[256];
    byte blue[]=new byte[256];
    byte alpha[]=new byte[256];
    for (int i=0; i<256; i++) {
      red[i]=(byte)i;
      green[i]=(byte)i;
      blue[i]=(byte)i;
      alpha[i]=(byte)255;
    }
    cm=new IndexColorModel(8,256,red,green,blue,alpha);
  }

public void init() 
  {
    try {
      norm=new Normal();
      showStatus("Reading normals...");
      URL url=new URL(getCodeBase(),getParameter("normals"));
      norm.read(url.openStream());
      showStatus("Ready.");
    } catch (Exception e) { System.err.println(e); }
  }

public void update(Graphics g)
  {
    paint(g);
  }

public void paint(Graphics g)
  {
    if (img==null) img=createImage(norm.getImageSource(cm,0,0));
    Rectangle rect=bounds();
    g.drawImage(img,rect.x,rect.y,rect.width,rect.height,null);
  }

public void pointLight(int x, int y)
  {
    Rectangle rect=bounds();
    double xx=-2.0*((double)x/(double)rect.width)+1.0;
    double yy=-2.0*((double)y/(double)rect.height)+1.0;
    
    img=createImage(norm.getImageSource(cm,xx,yy));
    repaint();
  }

public boolean mouseDown(Event evt, int x, int y) 
  {
    pointLight(x,y);
    return true;
  }

public boolean mouseMove(Event evt, int x, int y) 
  {
    pointLight(x,y);
    return true;
  }

public boolean mouseDrag(Event evt, int x, int y) 
  {
    pointLight(x,y);
    return true;
  }

public boolean mouseUp(Event evt, int x, int y) 
  {
    pointLight(x,y);
    return true;
  }

public void start()
  {
  }
  
public void stop()
  {
  }
}


