/*
yig3.java       by Julian Haight
=========

This is the classic yig.  Don't ask me why it's called yig, it just is.
You have seen this in many incarnations - mainly screen-blankers.  This one
is unique in that it calculates values for all three dimensions: X,Y and Z.
Most yig programs just do X and Y.  Any appearance of depth is just an
illusion.  In fact, any appearance of depth is an illusion in my version too,
because the Z value dosn't come into the calcultion of the lines.  It is
however used in the calculation of color.  Each point that is drawn is
mapped in 3-D from 0-255 pixels.  The X value cooresponds to red (left is
less, right is more).  The Y value cooresponds to Green (top is less, bottom
is more).  And the Z value cooresponds to Blue (0 is less, 255 is more).
This gives me a full color cube.

The bar at the bottom of the screen shows the full range of color for the
current line.  The left side is one end-point and the right side is the
other.  This allows you to see the whole pallete for any instant.

If you have any comments or questions, contact me via my web site:
http://www.julianhaight.com/
*/

import java.awt.*;

public class yig3 extends java.applet.Applet implements Runnable {
  point p1,p2;                         //Points at each end of line
  boolean time_to_die;                 //Notify to die.
  int MAX=255;                         //Max colors/size of window
  int MAXV=6;                         //Max Velocity of any point-channel

    public void init() {
      long lasttime;
      p1 = new point(MAX, MAXV);
      p2 = new point(MAX, MAXV);
      p1.rand(); p2.rand();            //Randomize points
      resize(MAX,MAX+20);              //Set window size
    }

    public void run() {
      do {
        repaint();                     //Repainting's our business
        try {
          Thread.sleep(100);           //Values don't seem to do much
        } catch (InterruptedException e) {  //don't know quite what this does
          return;
        }
      } while (!time_to_die);          //Go until time to die
    }

    public void start() {
      time_to_die=false;
      (new Thread(this)).start();      //Start-up
    }

    public void stop() {               //Stop it!
      time_to_die=true;
    }

    public void paint(Graphics g) {    //Don't bother
      Dimension d=size();
      g.setColor(new Color(0,0,0));    //Set color for background
      g.fillRect(0,0, d.width, d.height);  //Draw Backround
    }

    public void update(Graphics g) {   //Use update for flicker-free painting
      int count;                       //For each pallete color
      p1.move(); p2.move();            //Points move themselves
      float dx,dy,dz;                  //Delta (change in) X,Y and Z
      short x1,y1,z1,x2,y2,z2;         //Coordinates for each line-segment
      dx=(p1.x-p2.x)/MAX;              //Calculate Delta values
      dy=(p1.y-p2.y)/MAX;
      dz=(p1.z-p2.z)/MAX;
      for (count=0; count<=MAX-1; count++){   //Go through each pallete color
        x1=(short)(p1.x-dx*(float)count);     //Set each point based on delta
        x2=(short)(p1.x-dx*(float)(count+1));
        y1=(short)(p1.y-dy*(float)count);
        y2=(short)(p1.y-dy*(float)(count+1));
        z1=(short)(p1.z-dz*(float)count);
        z2=(short)(p1.z-dz*(float)(count+1));
        g.setColor(new Color(x1,y1,z1));      //Set color for line-segment
        g.drawLine(x1,y1,x2,y2);              //Draw segment
        g.drawLine(count,MAX+1,count,MAX+20); //Draw pallete-segment
      }
    }
}

class point {
      int MAX;                     
      int MAXV;                    
      float x;                         // Position
      float y;                         //Use floats for smooth movement
      float z;
      float xv;                        // Velocity
      float yv;
      float zv;

      point(int pmax, int pmaxv){  //Initialize to zero
        x=0;  y=0;  z=0;
        xv=0; yv=0; zv=0;
        MAX=pmax;
        MAXV=pmaxv;
      }
      void move(){                     //Move the point!
        x=x+xv;                        //Change position based on velocity
        y=y+yv;
        z=z+zv;
        if (x>MAX) {                   //This looks confusing, but it's pretty
          x=(2*MAX)-x;                 //simple.  If you hit the top or bottom,
          xv=-xv;                      //change direction and 'bounce' the
          addrand();                   //position the other way.
        } else if (x<0) {              
          x=-x;
          xv=-xv;
          addrand();
        }
        if (y>MAX) {                   //For Y too.
          y=(2*MAX)-y;
          yv=-yv;
          addrand();
        } else if (y<0) {
          y=-y;
          yv=-yv;
          addrand();
        }
        if (z>MAX) {                   //And Z.
          z=(2*MAX)-z;
          zv=-zv;
          addrand();
        } else if (z<0) {
          z=-z;
          zv=-zv;
          addrand();
        }
      }
      void set(point p){               //A way to copy one point to another
        x=p.x;
        y=p.y;
        z=p.z;
        xv=p.xv;
        yv=p.yv;
        zv=p.zv;
      }

      void addrand(){                     //Add a little randomness
        xv=xv+rnd((float).1)-(float).05; //This should be a constant 
        yv=yv+rnd((float).1)-(float).05;  
        zv=zv+rnd((float).1)-(float).05;
      }

      float rnd (float n) {            //Creates a random number from 0 to n
        return (float)Math.random() * n;
      }

      void rand(){                     //Randomize yourself.
        x=rnd(MAX);
        y=rnd(MAX);
        z=rnd(MAX);
        xv=rnd(MAXV*2)-MAXV;
        yv=rnd(MAXV*2)-MAXV;
        zv=rnd(MAXV*2)-MAXV;
      }
}


