import java.awt.*;
import java.applet.*;
import java.awt.image.IndexColorModel;
import java.awt.image.MemoryImageSource;

public class demo extends Applet implements Runnable {
  static final int xsize = 640;
  static final int ysize = 400;

  static final int winsize = 50;

  IndexColorModel cmodel;
  byte scr[];
  byte xred[];
  byte xgreen[];
  byte xblue[];
  int posx,posy;

  static final byte pic[] = {
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,0,2,2,0,0,3,3,0,0,0,0,0,0,0,0,
    1,0,0,2,2,0,3,3,3,0,0,0,0,0,0,0,
    1,0,0,0,2,2,3,3,3,0,0,0,0,0,0,0,
    1,0,0,0,2,2,3,3,0,0,0,0,0,0,0,0,
    1,0,0,0,0,3,3,0,0,0,0,0,0,0,0,0,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
  };
  /*
  st0tic final byte pic[] = {
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,1,1,1,1,1,1,0,2,2,2,2,2,2,0,
    0,0,1,1,1,1,1,1,0,2,2,2,2,2,2,0,
    0,0,1,1,1,1,1,1,0,2,2,2,2,2,2,0,
    0,0,1,1,1,0,0,0,0,0,0,0,2,2,2,0,
    0,0,1,1,1,0,0,0,0,0,0,0,2,2,2,0,
    0,0,1,1,1,1,1,0,0,0,2,2,2,2,2,0,
    0,0,1,1,1,1,1,0,0,0,2,2,2,2,2,0,
    0,0,1,1,1,1,1,0,0,0,2,2,2,2,2,0,
    0,0,1,1,1,0,0,0,0,0,0,0,2,2,2,0,
    0,0,1,1,1,0,0,0,0,0,0,0,2,2,2,0,
    0,0,1,1,1,1,1,1,0,2,2,2,2,2,2,0,
    0,0,1,1,1,1,1,1,0,2,2,2,2,2,2,0,
    0,0,1,1,1,1,1,1,0,2,2,2,2,2,2,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };*/
  static int dist = 400;
  static final int mirror = 300;
  static int cs = 60;

  static final int x3d[] = {cs,-cs, cs,-cs, cs,-cs, cs,-cs};
  static final int y3d[] = {cs, cs,-cs,-cs, cs, cs,-cs,-cs};
  static final int z3d[] = {cs, cs, cs, cs,-cs,-cs,-cs,-cs};

  static final int p[][] = {
    {4,0,2,6},
    {0,1,3,2},
    {1,5,7,3},
    {5,4,6,7},
    {0,4,5,1},
    {2,3,7,6}
  };

  int count=0;
  
  static final int nv[][] = {
    {5,4},
    {4,0},
    {0,1},
    {1,5},
    {7,5},
    {4,6}
  }; 
  
  static final int[] nz = new int[6];

  static final Color col[] = {
    new Color( 50,50,50 ),
    new Color( 75,75,75 ),
    new Color( 100,100,100 ),
    new Color( 125,125,125 ),
    new Color( 150,150,150 ),
    new Color( 175,175,175 ),
  };

  static final Color[] colors = new Color[50];
  static final Color[] mcolors = new Color[50];
  
  int[] x3r,y3r,z3r;
  int[] x2d,y2d;
  int[] x2m,y2m;
  double rx,ry,rz=0;

  Image e3,pr,rs;
  AudioClip rythm,rythm2,rythm3;

  Graphics gr;
  Thread tr;
  Image outimage;
  
  public void init() {
    super.init();
    setLayout(null);
    resize(xsize, ysize);
  }
  
  public void start() {
    outimage = createImage(xsize, ysize);
    if (tr == null) {
      tr = new Thread(this);
      tr.start();
    }
  }
  
  public void stop() {
  	rythm.stop();
    if (tr != null){
      tr.stop();
      tr = null;
    }
  }
  
  public void run() {
    gr = outimage.getGraphics();

    rythm = getAudioClip(getCodeBase(),"alpha.au");
    //rythm2 = getAudioClip(getCodeBase(),"wizardry.au");
    //rythm3 = getAudioClip(getCodeBase(),"paid.au");
    rythm.loop();
    //cube();
	//jelly();
    intro();
    tunnel();
    cube();
    credits();
    theend();
  }

  public void update(Graphics g){
  }

  public void repaint(){
    paint(getGraphics());
  }
  public void paint(Graphics g){
    g.drawImage(outimage, 0, 0, null);
  }

  public void jelly() {
	gr = outimage.getGraphics();
	int px[]=new int[4];
	int py[]=new int[4];
    x2d=new int[8];
    y2d=new int[8];
    x2m=new int[8];
    y2m=new int[8];
    x3r=new int[8];
    y3r=new int[8];
    z3r=new int[8];

dist = 100;
cs = 13;
	
    for( int i=0; i<50;i++ ) mcolors[i] = new Color(2*i+25,2*i+25,4*i+50);
    for( int i=0; i<50;i++ ) colors[i] = new Color(4*i+50,4*i+50,4*i+50);
	for( int teller=0;teller<300;teller++) {
		try { Thread.sleep(20); } catch (Exception e) {}
		gr.copyArea(0,0,xsize-winsize,winsize,winsize,0);
		gr.setColor(colors[0]);
		gr.fillRect(0,0,winsize,winsize);
		rx+=0.03;
		ry+=0.05;
		rz+=0.02;
		rotate();
		shade();
		proj2();
      for(int n=0; n<6; n++) {
        if( (y2m[p[n][2]]-y2m[p[n][1]])*(x2d[p[n][3]]-x2d[p[n][2]]) > (x2d[p[n][2]]-x2d[p[n][1]])*(y2m[p[n][3]]-y2m[p[n][2]]) ) {
          gr.setColor((nz[n]>0) ? mcolors[nz[n]>>2] : mcolors[0]);
          for(int i=0; i<4; i++) {
            px[i]=x2d[p[n][i]]+(xsize>>1);
            py[i]=y2m[p[n][i]]+(ysize>>2);
          }
          gr.fillPolygon(px,py,4);
        }
      }
	  for(int i=0; i<winsize;i++)
	    gr.copyArea((i>>2)*winsize,i,winsize,1,-((i>>2)*winsize),winsize);
	  repaint();
	  }

 } 

/*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
  public void tunnel() {
    precalc();
    gr.setColor(new Color(0, 0, 0));
    gr.fillRect(0, 0, xsize, ysize);
    for (int posisjon=0; posisjon<100; posisjon++) {
      try {
        Thread.sleep(0L, 1);
      } catch (InterruptedException e) {}
      
      for (int i = 0; i < 256; i++) {
        xred[i]   = (byte) ((pic[((posx+i)&15)+((7+posy+(i>>4)&15)<<4)]^3)<<6);
        xgreen[i] = (byte) (pic[((4+posx+i)&15)+((5+posy+(i>>4)&15)<<4)]<<6);;
        xblue[i]  = (byte) (pic[((7+posx+i)&15)+((posy+(i>>4)&15)<<4)]<<6);;
      }
      posx=(int)((Math.sin((double)posisjon/10)*50/Math.PI)+posisjon);
      posy=(int)((Math.cos((double)posisjon/10)*200/Math.PI));
      
      /*     xred[post]=(byte)255;
      xblue[(135+post)&255]=(byte)255;
      post=(post+17)%255;*/
      
      cmodel = new IndexColorModel(8, 256, xred, xgreen, xblue);	    
//      outimage = createImage(new MemoryImageSource(xsize, ysize, cmodel, scr, 0, xsize));
      gr.drawImage(createImage(new MemoryImageSource(xsize, ysize, cmodel, scr, 0, xsize)), 0, 0, this);
      repaint();
//      outimage.flush();
    }
  }

  public void precalc() {
    scr = new byte[xsize*ysize];
    xred = new byte[256];
    xgreen = new byte[256];
    xblue = new byte[256];
    int z;
    double v;
    for(int x=-(xsize/2); x<(xsize/2); x++) {
      for(int y=-(ysize/2); y<(ysize/2); y++) {
        if((x!=0)||(y!=0)) {
          z= (int)(8000 / Math.sqrt(Math.pow(x,2)+Math.pow(y,2)));
          if(x!=0) v=( Math.atan2(x,y)*256/Math.PI); else v=Math.PI/2;
          scr[(x+(xsize/2))+((y+(ysize/2))*xsize)]= (byte)((((int)v&15)<<4) | ((int)z&15));
      	  scr[(x+(xsize/2))+((y+(ysize/2))*xsize)]= (byte)((((int)v&15)<<4) | ((int)z&15));
        }
      }
    }
  }
/*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
  public void credits() {
    Color fr = new Color(200,200,200);
    Color sh = new Color(0,0,0);
    Image cl = getImage(getCodeBase(),"credlogo.gif");
    gr.drawImage(cl,0,0,null);
    Image cs = getImage(getCodeBase(),"cred_scr.gif");
    gr.drawImage(cs,0,0,null);

    Color bg = new Color(60,80,60);
    for(int i=50; i>=0; i--) {
      try { Thread.sleep(20); } catch (InterruptedException e) {}
      gr.setColor(bg);
      gr.fillRect(0,0,xsize,ysize);
      box((int)(Math.cos(i*3.14159d/50d + 3.14159d)*200+249), (int)(Math.cos(i*3.14159d/50d + 3.14159d)*200+249), 321, 201);
      repaint();
    }

    for(int i=300; i>-200; i-=2) {
      try { Thread.sleep(20); } catch (InterruptedException e) {}

      gr.drawImage(cl,50,50,null);
      gr.drawImage(cs,50,i,null);

      gr.setColor(bg);
      gr.fillRect(49,0,322,49);
      gr.fillRect(49,251,322,ysize);

      gr.setColor(fr);
      gr.drawRect(49, 49, 322, 201);

      gr.setColor(sh);
      gr.fillRect(54, 251, 320, 3);
      repaint();
    }
    for(int i=0; i<50; i++) {
      try { Thread.sleep(20); } catch (InterruptedException e) {}
      gr.setColor(bg);
      gr.fillRect(0,0,xsize,ysize);
      box((int)(Math.cos(i*3.14159d/50d + 3.14159d)*200+249), (int)(Math.cos(i*3.14159d/50d + 3.14159d)*200+249), 322, 202);
      repaint();
    }
    cs.flush();
    cl.flush();
  }
/*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
  public void intro() {
    e3 = getImage(getCodeBase(),"e3.gif");
    gr.drawImage(e3, 80, 50, null);
    pr = getImage(getCodeBase(),"presents.gif");
    gr.drawImage(pr, 80, 50, null);
    rs = getImage(getCodeBase(),"rs.gif");
    gr.drawImage(rs, 80, 50, null);

    Color c1 = new Color(80,50,80);
    Color c2 = new Color(120,75,120);

    gr.setColor(c1);
    gr.fillRect(0,0,xsize,ysize);
    repaint();
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {}

    int[] p2x={xsize,xsize,xsize,xsize,xsize};
    int[] p2y={ysize,ysize,ysize,ysize,ysize};

    for(int i=0; i<80; i++) {
      int a=(int)(Math.cos(i*3.14159/50d+3.14159d)*100+100)+i*xsize/100;
      int b=(int)(Math.cos(i*3.14159/50d+3.14159d)*100+ysize);

      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}

      p2x[1]=(a<xsize?xsize-a:0);
      p2x[2]=(a<xsize?xsize-a:0);
      p2y[2]=(a>xsize?ysize-(a-xsize):ysize);
      p2x[3]=(b>ysize?xsize-(b-ysize):xsize);
      p2y[3]=(b<ysize?ysize-b:0);
      p2y[4]=(b<ysize?ysize-b:0);

      gr.setColor(c1);
      gr.fillRect(0,0,xsize,ysize);
      gr.setColor(c2);
      gr.fillPolygon(p2x,p2y,5);
      repaint();
    }

    for(int i=50; i>=0; i--) {
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}

      gr.setColor(c1);
      gr.fillRect(0,0,xsize,ysize);
      gr.setColor(c2);
      gr.fillPolygon(p2x,p2y,5);
      box(79, (int)(Math.cos(i*3.14159d/50d + 3.14159d)*200+249), 482, 302);
      repaint();
    }

    for(int i=0; i<100; i++) {
      gr.drawImage(e3, 80, 50, null);
      repaint();
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}
    }
    for(int i=0; i<50; i++) {
      gr.drawImage(pr, 80, 50, null);
      repaint();
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}
    }
    for(int i=0; i<100; i++) {
      gr.drawImage(rs, 80, 50, null);
      repaint();
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}
    }

    for(int i=0; i<50; i++) {
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}

      gr.setColor(c1);
      gr.fillRect(0,0,xsize,ysize);
      gr.setColor(c2);
      gr.fillPolygon(p2x,p2y,5);
      box(79, (int)(Math.cos(i*3.14159d/50d + 3.14159d)*200+249), 482, 302);
      repaint();
    }
    e3.flush();
    pr.flush();
    rs.flush();

    for(int i=80; i>=0; i--) {
      int a=(int)(Math.cos(i*3.14159/50d+3.14159d)*100+100)+i*xsize/100;
      int b=(int)(Math.cos(i*3.14159/50d+3.14159d)*100+ysize);

      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}

      p2x[1]=(a<xsize?xsize-a:0);
      p2x[2]=(a<xsize?xsize-a:0);
      p2y[2]=(a>xsize?ysize-(a-xsize):ysize);
      p2x[3]=(b>ysize?xsize-(b-ysize):xsize);
      p2y[3]=(b<ysize?ysize-b:0);
      p2y[4]=(b<ysize?ysize-b:0);

      gr.setColor(c1);
      gr.fillRect(0,0,xsize,ysize);
      gr.setColor(c2);
      gr.fillPolygon(p2x,p2y,5);
      repaint();
    }

  }

  public void box(int x, int y, int xs, int ys) {
    Color fr = new Color(200,200,200);
    Color sh = new Color(0,0,0);
    gr.setColor(sh);
    gr.fillRect(x+4,y+4,xs,ys);
    gr.fillRect(x,y,xs,ys);
    gr.setColor(fr);
    gr.drawRect(x,y,xs,ys);
  }
/*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
  public void cube() {
    x2d=new int[8];
    y2d=new int[8];
    x2m=new int[8];
    y2m=new int[8];
    x3r=new int[8];
    y3r=new int[8];
    z3r=new int[8];

    Color topc = new Color(150,150,250);
    Color botc = new Color(50,50,175);
    gr.setColor(botc);
    for(int i=ysize; i>=0; i-=10) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {}
      gr.fillRect(0,i,xsize,ysize);
      repaint();
    }

    gr.setColor(topc);
    for(int i=0; i<ysize>>2; i+=10) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {}
      gr.fillRect(0,0,xsize,i);
      repaint();
    }

    for( int i=0; i<50;i++ ) mcolors[i] = new Color(2*i+25,2*i+25,4*i+50);
    for( int i=0; i<50;i++ ) colors[i] = new Color(4*i+50,4*i+50,4*i+50);

    int px[]=new int[4];
    int py[]=new int[4];
    int ny;

    for(int timer=500; timer>0; timer--) {
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}
      gr.setColor(topc);

      gr.fillRect(0,0,xsize,ysize>>2);
      gr.setColor(botc);
      gr.fillRect(0,ysize>>2,xsize,ysize);
  
      count++;  
      rx+=0.03;
      ry+=0.05;
      rz+=0.02;
      rotate();
      shade();
      proj();
      
      for(int n=0; n<6; n++) {
        if( (y2m[p[n][2]]-y2m[p[n][1]])*(x2d[p[n][3]]-x2d[p[n][2]]) > (x2d[p[n][2]]-x2d[p[n][1]])*(y2m[p[n][3]]-y2m[p[n][2]]) ) {
          gr.setColor((nz[n]>0) ? mcolors[nz[n]>>2] : mcolors[0]);
          for(int i=0; i<4; i++) {
            px[i]=x2d[p[n][i]]+(xsize>>1);
            py[i]=y2m[p[n][i]]+(ysize>>2);
          }
          gr.fillPolygon(px,py,4);
        }
      }
      
      for(int n=0; n<6; n++) {
        if( (y2d[p[n][2]]-y2d[p[n][1]])*(x2d[p[n][3]]-x2d[p[n][2]]) < (x2d[p[n][2]]-x2d[p[n][1]])*(y2d[p[n][3]]-y2d[p[n][2]]) ) {
          gr.setColor((nz[n]>0) ? colors[nz[n]>>2] : colors[0]);
          for(int i=0; i<4; i++) {
            px[i]=x2d[p[n][i]]+(xsize>>1);
            py[i]=y2d[p[n][i]]+(ysize>>2);
          }
          gr.fillPolygon(px,py,4);
        }
      }
      repaint();
    }
  }

  public final void shade() {
     for( int n=0; n<6;n++) nz[n]=-(z3r[nv[n][1]]-z3r[nv[n][0]]);
  } 
  
  public final void rotate() {
    double sx=Math.sin(rx);
    double sy=Math.sin(ry);
    double sz=Math.sin(rz);
    double cx=Math.cos(rx);
    double cy=Math.cos(ry);
    double cz=Math.cos(rz);
    for(int i=0; i<8;i++) {
      y3r[i]=(int)((x3d[i]*cz-y3d[i]*sz)*sx+((x3d[i]*sz+y3d[i]*cz)*cy-z3d[i]*sy)*cx);
      z3r[i]=(int)((x3d[i]*cz-y3d[i]*sz)*cx-((x3d[i]*sz+y3d[i]*cz)*cy-z3d[i]*sy)*sx);
      x3r[i]=(int)((x3d[i]*sz+y3d[i]*cz)*sy+z3d[i]*cy);
    }
  }
  
  public final void proj() {
    int zd; 
    for(int i=0; i<8; i++) {
      z3r[i]+=Math.sin(count/10d)*100;  
      x3r[i]+=Math.cos(count/10d)*100;      
      y3r[i]-=Math.sin(count/15d)*40;
      
      x2d[i]=dist*x3r[i]/(dist+z3r[i]);
      y2d[i]=dist*y3r[i]/(dist+z3r[i]);

      y2m[i]=dist*(-y3r[i]+mirror)/(dist+z3r[i]);
    }
  }
  public final void proj2() {
  	int zd;
	for(int i=0;i<8;i++) {
      x2d[i]=dist*x3r[i]/(dist+z3r[i]);
      y2d[i]=dist*y3r[i]/(dist+z3r[i]);
	}
	}
/*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
  public void theend() {
    Image te = getImage(getCodeBase(),"theend.gif");
    gr.drawImage(te,120,150,null);
    Color bg = new Color(60,80,60);
    gr.setColor(bg);
    gr.fillRect(0,0,xsize,ysize);
    repaint();
    try { Thread.sleep(3000); } catch (InterruptedException e) {}

    while( true ) {
      try { Thread.sleep(20); } catch (InterruptedException e) {}
      gr.drawImage(te,120,150,null);
      repaint();
    }
  }
}
