import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.applet.Applet;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.*;

public class Bug  extends Applet {
  public BranchGroup createSceneGraph() {
    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();

    // Create the transform group node and initialize it to the
    // identity.  Enable the TRANSFORM_WRITE capability so that
    // our behavior code can modify it at runtime.  Add it to the
    // root of the subgraph.
    TransformGroup objTrans = new TransformGroup();
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objRoot.addChild(objTrans);

    // Create a simple shape leaf node, add it to the scene graph.
    objTrans.addChild(new ColorCube(0.4));

    // Create a new Behavior object that will perform the desired
    // operation on the specified transform object and add it into
    // the scene graph.
    Transform3D yAxis = new Transform3D();
    Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
                                    0, 0,
                                    4000, 0, 0,
                                    0, 0, 0);

    RotationInterpolator rotator =
      new RotationInterpolator(rotationAlpha, objTrans, yAxis,
                               0.0f, (float) Math.PI*2.0f);
    BoundingSphere bounds =
      new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
    rotator.setSchedulingBounds(bounds);
    objTrans.addChild(rotator);

    return objRoot;
  }

  public Bug() {
    setLayout(new BorderLayout());
    GraphicsConfiguration config =
      SimpleUniverse.getPreferredConfiguration();

    MyCanvas3D c = new MyCanvas3D(config);
    add("Center", c);

    // Create a simple scene and attach it to the virtual universe
    BranchGroup scene = createSceneGraph();
    SimpleUniverse u = new SimpleUniverse(c);

    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), Float.MAX_VALUE);
    TransformGroup viewpl = u.getViewingPlatform().getViewPlatformTransform();

    MouseRotate    mrot   = new MouseRotate(MouseBehavior.INVERT_INPUT);
    mrot.setTransformGroup(viewpl);
    scene.addChild(mrot);
    mrot.setSchedulingBounds(bounds);
    // Following line will get rid of X movement, pure Y rotations only.
    mrot.setFactor(mrot.getXFactor(), 0.0);
    
    MouseTranslate mtrans = new MouseTranslate(MouseBehavior.INVERT_INPUT);
    mtrans.setTransformGroup(viewpl);
    scene.addChild(mtrans);
    mtrans.setSchedulingBounds(bounds);
    
    MouseZoom      mzoom  = new MouseZoom(MouseBehavior.INVERT_INPUT);
    mzoom.setTransformGroup(viewpl);
    scene.addChild(mzoom);
    mzoom.setSchedulingBounds(bounds);

    // Add some lights
    AmbientLight al = new AmbientLight();
    al.setInfluencingBounds(bounds);
    scene.addChild(al);

    DirectionalLight dl = new DirectionalLight();
    dl.setDirection(0, 0, -1);
    dl.setInfluencingBounds(bounds);
    scene.addChild(dl);
    

    // This will move the ViewPlatform back a bit so the
    // objects in the scene can be viewed.
    u.getViewingPlatform().setNominalViewingTransform();

    // Have Java 3D perform optimizations on this scene graph.
    scene.compile();

    u.addBranchGraph(scene);
  }

  //
  // The following allows HelloUniverse to be run as an application
  // as well as an applet
  //
  public static void main(String[] args) {
    new MainFrame(new Bug(), 256, 256);
  }
}


class MyCanvas3D extends Canvas3D {
  private Point3d     vertices[];
  private Transform3D imgtovworld;
  private boolean     mono = false;

  public MyCanvas3D(java.awt.GraphicsConfiguration graphicsConfiguration) {
    super(graphicsConfiguration);

    vertices    = new Point3d[5];
    vertices[0] = new Point3d();
    vertices[1] = new Point3d();
    vertices[2] = new Point3d();
    vertices[3] = new Point3d();
    vertices[4] = new Point3d();

    imgtovworld = new Transform3D();
  }

   public void preRender() {
     getImagePlateToVworld(imgtovworld);
     getPixelLocationInImagePlate( 0, 0, vertices[4]);
     imgtovworld.transform(vertices[4]);
   }

  public void renderField(int fieldDesc) {
    getImagePlateToVworld(imgtovworld);
    switch (fieldDesc) {
      case Canvas3D.FIELD_LEFT  :
        getPixelLocationInImagePlate( 0, 0, vertices[0]);
        imgtovworld.transform(vertices[0]);
        mono = false;
        break;
      case Canvas3D.FIELD_RIGHT :
        getPixelLocationInImagePlate( 0, 0, vertices[1]);
        imgtovworld.transform(vertices[1]);
        mono = false;
        break;
      case Canvas3D.FIELD_ALL   :
        getPixelLocationInImagePlate( 0, 0, vertices[2]);
        imgtovworld.transform(vertices[2]);
        mono = true;
        break;
    }
  }

  public void postRender() {
    getImagePlateToVworld(imgtovworld);
    getPixelLocationInImagePlate( 0, 0, vertices[3]);
    imgtovworld.transform(vertices[3]);

/*
      if (vertices[3].distance(vertices[4]) > 0.0001) {
        System.out.println("PRE   : " + vertices[4]);
        System.out.println("POST  : " + vertices[3]);
        System.out.println("DIST  : " + vertices[3].distance(vertices[4]));
        System.out.println("--------------------------------");
      }
*/
    if (mono) {
      if (vertices[3].distance(vertices[2]) > 0.0001) {
        System.out.println("ALL   : " + vertices[2]);
        System.out.println("POST  : " + vertices[3]);
        System.out.println("DIST  : " + vertices[3].distance(vertices[2]));
        System.out.println("--------------------------------");
      }
    } else {
      if (vertices[3].distance(vertices[0]) > 0.0001) {
        System.out.println("LEFT  : " + vertices[0]);
        System.out.println("POST  : " + vertices[3]);
        System.out.println("DIST  : " + vertices[3].distance(vertices[0]));
        System.out.println("--------------------------------");
      }
      if (vertices[3].distance(vertices[1]) > 0.0001) {
        System.out.println("RIGHT : " + vertices[1]);
        System.out.println("POST  : " + vertices[3]);
        System.out.println("DIST  : " + vertices[3].distance(vertices[1]));
        System.out.println("--------------------------------");
      }
    }
  }
}
