/*
 *   Transformations

*/

import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
//import javax.swing.JFrame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SimpleGeometry extends JFrame{
  Vector3d euler;
  Canvas3D canvas;
  TransformGroup objScale;
  TransformGroup triadTG;
  TransDialog dlgTrans;
  Transform3D t3d = new Transform3D();

  public BranchGroup createSceneGraph(SimpleUniverse u) {
	// Create the root of the branch graph
	  BranchGroup objRoot = new BranchGroup();

    objScale = new TransformGroup();
    triadTG = new TransformGroup();
    triadTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    objRoot.addChild(objScale);
    objRoot.addChild(triadTG);

    objScale.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    objScale.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	  objScale.addChild(new ColorCube());
    Appearance lookCoord = new Appearance();
    Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
    Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
	  lookCoord.setMaterial(new Material(red, black,red, white, 100.0f));
    Triad triad = new Triad(lookCoord);
    triadTG.addChild(triad);
    Transform3D initTriadTransform = new Transform3D();
    initTriadTransform.set (new Vector3f (1f , -1f, 1f));
    triadTG.setTransform(initTriadTransform);

    objRoot.compile();
 	  return objRoot;
  }

  public void createInterface() {
      Container cp = this.getContentPane();
      JToolBar toolBar = new JToolBar();
      JButton dlgButton = new JButton("Dialog");  //transform dialog
      toolBar.add(dlgButton);
      cp.add(toolBar, "North");
      cp.add(canvas, "Center");

      dlgButton.addActionListener ( new ActionListener () {
        public void actionPerformed(ActionEvent e) {
           dlgTrans.setVisible(true);
        }
      });

      this.addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent evt) {
            System.exit(0);
          }
      });
      this.pack();
      this.setVisible(true);
  }

  public void doTransforms(int transID, double xRot, double yRot, double zRot,
                           double xTransl, double yTransl, double zTransl, boolean bIncr) {
    Transform3D rot1 = new Transform3D();
    Transform3D rot2 = new Transform3D();
    Transform3D rot3 = new Transform3D();
    Transform3D transl = new Transform3D();
    Transform3D erot = new Transform3D();
    Matrix4f matr = new Matrix4f();
    if(! bIncr) {
      t3d.setIdentity();
    }
    switch(transID) {

      case LOCALROTATION:
         rot1.rotX(Math.toRadians(xRot));
         rot2.rotY(Math.toRadians(yRot));
         rot3.rotZ(Math.toRadians(zRot));
         transl.setTranslation(new Vector3d(xTransl,yTransl,zTransl));
         t3d.mul(rot1);
         t3d.mul(rot2);
         t3d.mul(rot3);
         t3d.mul(transl);
         objScale.setTransform(t3d);
      break;

      case GLOBALROTATION:
        Transform3D currentTr = new Transform3D ();
        Transform3D triadTr = new Transform3D ();
        triadTG.getTransform(triadTr);
        Vector3d center = new Vector3d ();
        triadTr.get (center);
        objScale.getTransform(currentTr);
        rot1.rotX(Math.toRadians(xRot));
        rot2.rotY(Math.toRadians(yRot));
        rot3.rotZ(Math.toRadians(zRot));
        t3d = arbitraryTransform(currentTr, rot1, rot2, rot3, center);
        transl.setTranslation(new Vector3d(xTransl,yTransl,zTransl));
        t3d.mul(transl);
        objScale.setTransform(t3d);

    }
  }

  public SimpleGeometry () {
    dlgTrans = new TransDialog(this);
    canvas = new Canvas3D(null);
    canvas.setSize(600,480);
    createInterface();
    SimpleUniverse u = new SimpleUniverse(canvas);
    BranchGroup scene = createSceneGraph(u);

    TransformGroup viewTG = u.getViewingPlatform().getViewPlatformTransform ();
    Transform3D viewTransform = new Transform3D();
    viewTG.getTransform(viewTransform);

    Vector3d originTranslate = new Vector3d(0.0 ,0.0 ,10.);
    Transform3D transl = new Transform3D();
    transl.setTranslation(originTranslate);
    viewTransform.mul(transl);
    viewTG.setTransform(viewTransform);
    u.addBranchGraph(scene);

  }

  //**************** rotation relatively to an arbitrary point ****
   public Transform3D arbitraryTransform(Transform3D currXform,
                                  Transform3D transformX,
                                  Transform3D transformY,
                                  Transform3D transformZ,
                                  Vector3d point) {

    Matrix3d rotXform = new Matrix3d ();
    Matrix3d rotXformInvert = new Matrix3d ();
    Transform3D rotateTransform = new Transform3D ();

    Transform3D newXform = new Transform3D(currXform);
    Transform3D lookatOffsetForward = new Transform3D ();
    lookatOffsetForward.set (new Vector3d (point.x, point.y, point.z));
    Transform3D lookatOffsetBack = new Transform3D ();
    lookatOffsetBack.set (new Vector3d (-point.x, -point.y, -point.z));
    // translate back to the origin
    newXform.mul (lookatOffsetBack, newXform);
   // get the current rotation matrix and invert it
    newXform.get (rotXform);
    rotXformInvert.invert (rotXform);
    rotateTransform.set (rotXformInvert);
    // 'derotate' the matrix
    newXform.mul (rotateTransform, newXform);
    // rotate the matrix by transformY
    if (transformY != null) {
        newXform.mul (transformY, newXform);
    }
    if (transformX != null) {
        newXform.mul (transformX, newXform);
    }
    if (transformZ != null) {
        newXform.mul (transformZ, newXform);
    }
   // rotate the matrix by the original rotate matrix
    rotateTransform.set (rotXform);
    newXform.mul (rotateTransform, newXform);
   // translate back to the lookat position
    newXform.mul (lookatOffsetForward, newXform);
    return newXform;
 }



  public static void main(String[] args) {

	      // Create a simple scene and attach it to the virtual universe

        SimpleGeometry sg = new SimpleGeometry();
  }

  static final int LOCALROTATION = 1;
  static final int GLOBALROTATION = 2;

}
