/*
 *      @(#)PickTestGeometry.java 1.5 99/05/19 09:38:17
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

//import com.sun.j3d.utils.behaviors.picking.*;
import com.sun.j3d.utils.picking.behaviors.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * PickTestGeometry shows how to use the Picking utilities on various GeometryArray
 * subclasses and Morph object.
 * Type of Geometry      : CompressedGeometry ( GullCG.java )
 *                         IndexedQuadArray ( CubeIQA.java )
 *                         TriangleArray ( TetrahedronTA.java )
 *                         IndexedTriangleArray ( TetrahedronITA.java )
 *                         TriangleFanArray ( OctahedronTFA.java )
 *                         IndexedTriangleFanArray ( OctahedronITA.java )
 *                         TriangleStripArray ( IcosahedronTFA.java )
 *                         IndexedTriangleStripArray ( IcosahedronITA.java )
 *
 * Morph Object uses :     QuadArray ( ColorCube.java, ColorPyramidDown.java, and
 *                         ColorPyramidUp.java ).
 */

public class PickTestGeometry extends Applet {
  
  private QuadArray geomMorph[] = new QuadArray[3];
  private Morph morph;

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

    // Create a Transformgroup to scale all objects so they
    // appear in the scene.
    TransformGroup objScale = new TransformGroup();
    Transform3D t3d = new Transform3D();
    t3d.setScale(1.0);
    objScale.setTransform(t3d);
    objRoot.addChild(objScale);
    
    // Create a bunch of objects with a behavior and add them
    // into the scene graph.
    
    int row, col;
    int numRows = 3, numCols = 4;
    
    for (int i = 0; i < numRows; i++) {
      double ypos = (double)(i - numRows/2) * 0.6;
      for (int j = 0; j < numCols; j++) {
        double xpos = (double)(j - numCols/2) * 0.45 + 0.25;
        objScale.addChild(createObject(i, j, 0.1,  xpos, ypos));
      }
    }

    BoundingSphere bounds =
      new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

    // Add a light.
    Color3f lColor = new Color3f(1.0f, 1.0f, 1.0f) ;
    Vector3f lDir  = new Vector3f(0.0f, 0.0f, -1.0f) ;

    DirectionalLight lgt = new DirectionalLight(lColor, lDir) ;
    lgt.setInfluencingBounds(bounds) ;
    objRoot.addChild(lgt) ;


    // Now create the Alpha object that controls the speed of the
    // morphing operation.
    Alpha morphAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE |
                                 Alpha.DECREASING_ENABLE,
                                 0, 0,
                                 4000, 1000, 500,
                                 4000, 1000, 500);
      
    // Finally, create the morphing behavior
    MorphingBehavior mBeh = new MorphingBehavior(morphAlpha, morph);  
    mBeh.setSchedulingBounds(bounds);
    objRoot.addChild(mBeh);
        
    PickRotateBehavior behavior = new PickRotateBehavior(objRoot, canvas, bounds); 
                                                        
    objRoot.addChild(behavior);
    
    PickZoomBehavior behavior2 = new PickZoomBehavior(objRoot, canvas, bounds);
                                                      
    objRoot.addChild(behavior2);
    PickTranslateBehavior behavior3 = new PickTranslateBehavior(objRoot, canvas, bounds);
                                                        
    objRoot.addChild(behavior3);


    // Let Java 3D perform optimizations on this scene graph.
    objRoot.compile();
 
    return objRoot;
  }
  

  private Group createObject(int i, int j, double scale, double xpos, double ypos) {
    
    Shape3D shape = null;
    Geometry geom = null;
     
    // Create a transform group node to scale and position the object.
    Transform3D t = new Transform3D();
    t.set(scale, new Vector3d(xpos, ypos, 0.0));
    TransformGroup objTrans = new TransformGroup(t);
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    objTrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
    
    // Create a second transform group node and initialize it to the
    // identity.  Enable the TRANSFORM_WRITE capability so that
    // our behavior code can modify it at runtime.
    TransformGroup spinTg = new TransformGroup();
    spinTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    spinTg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    spinTg.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
 
    Appearance appearance = new Appearance();
    
    int index = i * 4 + j;
    switch(index) {
    case 0:
      geom = new GullCG();
      break;
    case 1:
      geom = new TetrahedronTA();
      break;
    case 2:
      geom = new OctahedronTFA();  
      break;
    case 3:
      geom = new IcosahedronTSA();    
      break;
    case 4:
      geom = new CubeIQA();   
      break;
    case 5:
      geom = new TetrahedronITA();  
      break;
    case 6:
      geom = new OctahedronITFA();  
      break;
    case 7:
      geom = new IcosahedronITSA();  
      break;
    case 8:
      geomMorph[0] = new ColorPyramidUp();
      geom = geomMorph[0];
      break;
    case 9:
      geomMorph[1] = new ColorCube();
      geom = geomMorph[1];
      break;
    case 10:
      geomMorph[2] = new ColorPyramidDown();
      geom = geomMorph[2];
      break;
    case 11:
      // Morph node uses the geometry from ColorPyramidUp, ColorPyramidDown, and 
      // ColorCube. So do nothing here.
      break;

    }

    Material m = new Material() ;
        
    if(index<11) {
        // Geometry picking require this to be set.
        geom.setCapability(Geometry.ALLOW_INTERSECT);

        if (index == 0)
            m.setLightingEnable(true) ;
        else
            m.setLightingEnable(false) ;

        appearance.setMaterial(m) ;
        shape = new Shape3D(geom,appearance);
        shape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
        shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
        shape.setCapability(Shape3D.ENABLE_PICK_REPORTING);
        spinTg.addChild(shape);
    }
    else {
        m.setLightingEnable(false) ;
        appearance.setMaterial(m) ;
        morph = new Morph((GeometryArray[]) geomMorph, appearance);
        morph.setCapability(Morph.ALLOW_WEIGHTS_READ);
        morph.setCapability(Morph.ALLOW_WEIGHTS_WRITE);
        spinTg.addChild(morph); 
    }
     
    // add it to the scene graph. 
    objTrans.addChild(spinTg);    

    return objTrans;
  }
  
  public PickTestGeometry (){
    setLayout(new BorderLayout());
    GraphicsConfiguration config =
       SimpleUniverse.getPreferredConfiguration();

    Canvas3D c = new Canvas3D(config);
    add("Center", c);
    
    // Create a scene and attach it to the virtual universe
    BranchGroup scene = createSceneGraph(c);
    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);
  }
  
  
  public static void main(String argv[])
  {
    
    BranchGroup group;
    
    new MainFrame(new PickTestGeometry(), 700, 700);
  }
}

