import java.awt.*;
import java.awt.event.*;

import javax.media.j3d.*;
import javax.vecmath.*;

import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;

public class planes extends Frame
 implements ActionListener
{
// Declare a few static items
public static View v;
public static Button b1;
public static Button b2;

/*******************************************/

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);

  objTrans.addChild ( createPlane ( new Color3f ( 0.0f , 0.0f , 255f ) , 0.25 , 0.75 , 0.25, 0.75 , 0.0 , 0.0 ) );
  objTrans.addChild ( createPlane ( new Color3f ( 0.0f , 255.0f , 0.0f ) , 0.20 , 0.70 , 0.20, 0.70 , 0.5 , 0.5 ) );
  objTrans.addChild ( createLine ( new Color3f ( 255.0f , 255.0f , 255.0f ) , 0.25 , 0.75 , 0.25, 0.75 , 1.0 , 0.25 ) );
  objTrans.addChild ( createPoint ( new Color3f ( 255.0f , 0.0f , 0.0f ) , 0.50 , 0.70 , 0.3 ) );

  objRoot.compile();
  return objRoot;
  }

/************************************************/  

public BranchGroup createPlane ( Color3f qcolor
                               , double minx , double maxx
                               , double miny , double maxy
                               , double minz , double maxz 
                               )
    {
    Shape3D s3d = new Shape3D ();
    QuadArray qa = new QuadArray ( 4 , QuadArray.COORDINATES 
                                   | QuadArray.COLOR_3  | QuadArray.NORMALS
                                   );
    qa.setCoordinate ( 3
                     , new Point3d ( minx
                                   , miny
                                   , minz
                                   )
                         );
    qa.setColor ( 3 , qcolor );
    
    qa.setCoordinate ( 2 , new Point3d ( minx
                                       ,  maxy
                                       ,  minz
                                         )
                       );
    qa.setColor ( 2 , qcolor );
    
    qa.setCoordinate ( 1 , new Point3d ( maxx
                                         , maxy
                                         , minz
                                         )
                       );
    qa.setColor ( 1 , qcolor );
    
    qa.setCoordinate ( 0 , new Point3d ( maxx
                                         , miny
                                         , minz
                                         )
                       );
    qa.setColor ( 0 , qcolor );

    s3d.setGeometry ( qa );
    
    Appearance ap = new Appearance();
    
    PolygonAttributes polya = new PolygonAttributes (  ) ;
    polya.setCullFace ( PolygonAttributes.CULL_NONE );
    polya.setPolygonOffset ( 0.5f );
    ap.setPolygonAttributes ( polya );
    
    s3d.setAppearance ( ap );

    BranchGroup bg = new BranchGroup();
    TransformGroup tg = new TransformGroup ( );

    tg.addChild ( s3d );
    bg.addChild ( tg );
    return ( bg );
    }
  
/*******************************************/

public BranchGroup createPoint( Color3f color3f , double x , double y , double z )
  {
  Shape3D s3d = new Shape3D(); 

  PointArray pa = new PointArray( 1 , PointArray.COORDINATES |  PointArray.COLOR_3 );
  pa.setCoordinate ( 0 , new Point3f( (float) x , (float) y , (float) z ) );
  pa.setColor ( 0 , color3f );

  PointAttributes pointAtt = new PointAttributes();
  pointAtt.setPointSize( 3.0f );
  
  Appearance app = new Appearance();
  app.setPointAttributes ( pointAtt );
  
  s3d.setAppearance ( app );
  s3d.setGeometry( pa );

  BranchGroup bg = new BranchGroup();
  TransformGroup tg = new TransformGroup ( );
  tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

  tg.addChild ( s3d );
  bg.addChild ( tg );
  return ( bg );
  }

/*******************************************/

public BranchGroup createLine( Color3f color3f , double x1 , double y1 , double z1 , double x2 , double y2 , double z2 )
  {
  Shape3D s3d = new Shape3D();

  LineArray la = new LineArray( 2 , LineArray.COORDINATES | LineArray.COLOR_3 );
  Point3f p1 =  new Point3f ( (float) x1 , (float) y1 , (float) z1 );
  Point3f p2 =  new Point3f ( (float) x2 , (float) y2 , (float) z2 );
  
  la.setCoordinate ( 0, p1); 
  la.setCoordinate ( 1, p2);
			     
  la.setColor ( 0 , color3f );
  la.setColor ( 1 , color3f );

  s3d.setGeometry( la );

  BranchGroup bg = new BranchGroup();
  TransformGroup tg = new TransformGroup ( );
  
  tg.addChild ( s3d );
  bg.addChild ( tg );
  return ( bg );
  }
    
/*******************************************/

BranchGroup createViewGraph(View view , Canvas3D c3d, int num) 
  {
  BranchGroup viewRoot = new BranchGroup();
  
  // use same view distance as main view
  double viewDistance = view.getFieldOfView();
  
  // Calculate the distance from the to the imageplate.
  viewDistance = 1.0/Math.tan(viewDistance/2.0);
  
  // Assign this value to the ViewPlatform transform.
  Transform3D offset = new Transform3D();
  offset.set(new Vector3d(0.0, 0.0, viewDistance));
  
  TransformGroup spinTg = new TransformGroup();
  spinTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
  TransformGroup offTg = new TransformGroup();
  offTg.setTransform(offset);
  viewRoot.addChild(spinTg);
  spinTg.addChild(offTg);
  
  Transform3D yAxis = new Transform3D();
  Transform3D xAxis = new Transform3D();
  xAxis.rotZ(Math.PI/2.0d);
  
  RotationInterpolator rotator;
  
  if (num == 0) 
    {
    Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
    0, 0,
    3000, 0, 0,
    0, 0, 0);
  
    rotator =
    new RotationInterpolator(rotationAlpha, spinTg, xAxis,
    0.0f, (float) Math.PI*2.0f);
    }
  else
    {
    Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
    0, 0,
    7000, 0, 0,
    0, 0, 0);
    
    rotator =
    new RotationInterpolator(rotationAlpha, spinTg, 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);
  spinTg.addChild(rotator);
  
  PhysicalBody physicalBody = new PhysicalBody();
  PhysicalEnvironment physicalEnvironment = new PhysicalEnvironment();
  ViewPlatform viewPlatform = new ViewPlatform();
  offTg.addChild(viewPlatform);
  
  view.addCanvas3D(c3d);
  view.setPhysicalBody(physicalBody);
  view.setPhysicalEnvironment(physicalEnvironment);
  view.attachViewPlatform(viewPlatform);
  
  return viewRoot;
  }

/*******************************************************/

public static void main(String args[]) 
  {
  planes mv = new planes();
  mv.setLayout(new GridLayout(1, 3, 10, 10));
  
  Canvas3D suCanvas = new Canvas3D(null);
  // Handle the close event
  mv.addWindowListener
    (
    new WindowAdapter()
      {
      public void windowClosing(WindowEvent winEvent)
        {
        System.exit(0);
        }
      }
    );

  VirtualUniverse u = new VirtualUniverse();
  Locale l = new Locale (u);
  
  v = new View ();

  BranchGroup objRoot = mv.createSceneGraph();
  BranchGroup viewRoot = mv.createViewGraph( v , suCanvas, 0);
  v.setProjectionPolicy ( View.PARALLEL_PROJECTION );

  v.setFrontClipDistance( -500.0 );

  l.addBranchGraph(objRoot);
  l.addBranchGraph(viewRoot);
  
  mv.add(suCanvas);

  b1 = new Button ( "500.0 blue/green alternate" );
  b1.addActionListener ( mv );
  b2 = new Button ( "50000.0 blue on top" );
  b2.addActionListener ( mv );

  mv.add ( b1 );
  mv.add ( b2 );

  mv.setTitle("Why is blue always on top?");
  mv.setSize(512, 512);
  mv.show();
  }

/*******************************************************/

public void actionPerformed ( ActionEvent evt )
  {
  Object obj = evt.getSource();
  if ( obj == b1 )
    {
    v.setFrontClipDistance( -500.0 );
    }
  else if ( obj == b2 )
    {
    v.setFrontClipDistance( -50000.0 );
    }
  }
  
}
