/*
 *  Lab exercise 4.0
 *  CSc 471, Computer Graphics
 *  Copyright 1999-2001 Chris Buckalew
 */

/*--------------------------------------------------------------
 *  This code contains five examples of using transformation
 *  nodes to place two Java 3D primitives, a cylinder and
 *  a cone, in different locations.  Your job is to build a
 *  scene graph that shows a big "X" made of two cylinders, with
 *  points (cones) on each end.  Use multiple TransformGroup
 *  nodes and the two primitives to create this model.
 *------------------------------------------------------------*/


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

public class TransformLab extends Applet {

   private Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
   private Color3f white = new Color3f(1.0f, 1.0f, 1.0f);

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

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

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

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

       u.addBranchGraph(scene);
   }

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

      // Create light source
      // first bound its influence
      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);
    
      // now make the light itself
      DirectionalLight light = new DirectionalLight(new Color3f(1.0f, 1.0f, 1.0f),
                                                      new Vector3f( 0f,0f,-1f));
      light.setInfluencingBounds(bounds);
      objRoot.addChild(light);
    
      // make the transform that moves the whole model - this is for the
      //   mouse movements
      TransformGroup modelTrans = new TransformGroup();
    
      Transform3D trans = new Transform3D();
      // initially move it away from camera
      trans.setTranslation(new Vector3d(-2d, 0d, -5.0d));
      // and shrink everything so it fits in field of view
      trans.setScale(new Vector3d(0.2d, 0.2d, 0.2d));
      modelTrans.setTransform(trans);

      // necessary so mouse movements can read and change transform
      modelTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      modelTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    
      // Create the rotate behavior node
      MouseRotate modelRot = new MouseRotate();
      modelRot.setTransformGroup(modelTrans);
      modelTrans.addChild(modelRot);
      modelRot.setSchedulingBounds(bounds);

      // Create the zoom behavior node
      MouseZoom modelZoom = new MouseZoom();
      modelZoom.setTransformGroup(modelTrans);
      modelTrans.addChild(modelZoom);
      modelZoom.setSchedulingBounds(bounds);

      // Create the translate behavior node
      MouseTranslate modelTranslate = new MouseTranslate();
      modelTranslate.setTransformGroup(modelTrans);
      modelTrans.addChild(modelTranslate);
      modelTranslate.setSchedulingBounds(bounds);

      objRoot.addChild(modelTrans);

      // Here are five examples of using transforms

      modelTrans.addChild(buildFirstExample());    
 
      modelTrans.addChild(buildSecondExample());    

      modelTrans.addChild(buildThirdExample());    

      modelTrans.addChild(buildFourthExample());    

      modelTrans.addChild(buildFifthExample());    

        return objRoot;
   }

   private BranchGroup buildFirstExample () {
      // example 1 - the cylinder sees a rotation and the cone
      //             sees a translation

      BranchGroup example1 = new BranchGroup();
      // In the first example we rotate the cylinder under one
      //   transform and and move the cone up with another transform
    
      // Make the color
      Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
      Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
      Appearance example1App = new Appearance();
      example1App.setMaterial(new Material(
         black, black, new Color3f(1.0f,0.0f,1.0f), white, 80f));

      TransformGroup example1Trans1 = new TransformGroup();
      
      Transform3D trans = new Transform3D();
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example1Trans1.setTransform(trans);

      Cylinder example1Cyl = new Cylinder();
      example1Cyl.setAppearance(example1App);

      example1Trans1.addChild(example1Cyl);

      example1.addChild(example1Trans1);

      TransformGroup example1Trans2 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setTranslation(new Vector3d(0d, 2d, 0d));
      example1Trans2.setTransform(trans);

      Cone example1Cone = new Cone();
      example1Cone.setAppearance(example1App);
        
      example1Trans2.addChild(example1Cone);

      example1.addChild(example1Trans2);

      return example1;    

   }
 
   private TransformGroup buildSecondExample() {
      // example 2 - the cylinder sees a rotation and the cone
      //             sees a rotation and a translation

      TransformGroup example2 = new TransformGroup();
      // this transform just shifts right 5 units
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(5d, 0d, 0d));
      example2.setTransform(trans);
      
      // In the second example we rotate the cylinder under one
      //   transform and and rotate and translate the cone up
      //   with two more transforms
          
      // Make the color
      Appearance example2App = new Appearance();
      example2App.setMaterial(new Material(
         black, black, new Color3f(0.0f,1.0f,0.0f), white, 80f));

      TransformGroup example2Trans1 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example2Trans1.setTransform(trans);

      Cylinder example2Cyl = new Cylinder();
      example2Cyl.setAppearance(example2App);

      example2Trans1.addChild(example2Cyl);

      example2.addChild(example2Trans1);

      TransformGroup example2Trans2 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example2Trans2.setTransform(trans);

      TransformGroup example2Trans3 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setTranslation(new Vector3d(0d, 2d, 0d));
      example2Trans3.setTransform(trans);

      Cone example2Cone = new Cone();
      example2Cone.setAppearance(example2App);
          
      example2Trans3.addChild(example2Cone);

      example2Trans2.addChild(example2Trans3);
      
      example2.addChild(example2Trans2);

      return example2;    
 
   }
 
   private TransformGroup buildThirdExample() {
      // example 3 - the cylinder sees a rotation and the cone
      //             sees a rotation and a translation, but in
      //             the opposite order

      TransformGroup example3 = new TransformGroup();
      // this transform just shifts right 5 units
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(10d, 0d, 0d));
      example3.setTransform(trans);
      
      // Make the color
      Appearance example3App = new Appearance();
      example3App.setMaterial(new Material(
         black, black, new Color3f(1.0f,1.0f,0.0f), white, 80f));

      TransformGroup example3Trans1 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example3Trans1.setTransform(trans);

      Cylinder example3Cyl = new Cylinder();
      example3Cyl.setAppearance(example3App);

      example3Trans1.addChild(example3Cyl);

      example3.addChild(example3Trans1);

      TransformGroup example3Trans2 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setTranslation(new Vector3d(0d, 2d, 0d));
      example3Trans2.setTransform(trans);


      TransformGroup example3Trans3 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example3Trans3.setTransform(trans);

      Cone example3Cone = new Cone();
      example3Cone.setAppearance(example3App);
          
      example3Trans3.addChild(example3Cone);

      example3Trans2.addChild(example3Trans3);
      
      example3.addChild(example3Trans2);

      return example3;    

   }
 
   private TransformGroup buildFourthExample() {
      // example 4 - the cylinder sees a rotation and the cone
      //             sees a transform containing both a rotation
      //             and a translation, again in the wrong order

      TransformGroup example4 = new TransformGroup();
      // this transform just shifts right 5 units
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(15d, 0d, 0d));
      example4.setTransform(trans);
      
      // Make the color
      Appearance example4App = new Appearance();
      example4App.setMaterial(new Material(
         black, black, new Color3f(0.0f,0.0f,1.0f), white, 80f));

      TransformGroup example4Trans1 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example4Trans1.setTransform(trans);

      Cylinder example4Cyl = new Cylinder();
      example4Cyl.setAppearance(example4App);

      example4Trans1.addChild(example4Cyl);

      example4.addChild(example4Trans1);

      TransformGroup example4Trans2 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setTranslation(new Vector3d(0d, 2d, 0d));
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example4Trans2.setTransform(trans);
      
      Cone example4Cone = new Cone();
      example4Cone.setAppearance(example4App);
      
      example4Trans2.addChild(example4Cone);

      example4.addChild(example4Trans2);

      return example4;    

   }
 
   private TransformGroup buildFifthExample() {
      // example 5 - first rotate, add cylinder, then translate,
      //   then cone

      TransformGroup example5 = new TransformGroup();
      // this transform just shifts right 5 units
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(20d, 0d, 0d));
      example5.setTransform(trans);
      
      // Make the color
      Appearance example5App = new Appearance();
      example5App.setMaterial(new Material(
         black, black, new Color3f(0.0f,1.0f,1.0f), white, 80f));

      TransformGroup example5Trans1 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setRotation(new AxisAngle4f(0f,0f,1f,0.7865f));
      example5Trans1.setTransform(trans);

      Cylinder example5Cyl = new Cylinder();
      example5Cyl.setAppearance(example5App);

      example5Trans1.addChild(example5Cyl);

      TransformGroup example5Trans2 = new TransformGroup();
      
      trans.setIdentity();  
      trans.setTranslation(new Vector3d(0d, 2d, 0d));
      example5Trans2.setTransform(trans);
      
      Cone example5Cone = new Cone();
      example5Cone.setAppearance(example5App);
          
      example5Trans2.addChild(example5Cone);
 
      example5Trans1.addChild(example5Trans2);
        
      example5.addChild(example5Trans1);
      
      return example5;    
 
   }
 
   // The following allows TransformLab to be run as an application
   //     as well as an applet
   public static void main(String[] args) {
      new MainFrame(new TransformLab(), 1000, 750);
   }
}