It creates a Virtual Universe and a Locale and attaches to the Locale : Universe Node « 3D « Java






It creates a Virtual Universe and a Locale and attaches to the Locale

/* Author Claude G. Schwab 
 * Copyright (c) 2005  University of applied sciences 
 * Biel School of Engineering and Architecture, Switzerland.
 * http://www.hta-bi.bfh.ch
 * All Rights Reserved.
 * Compiled with SDK 1.4.1 and Java3D API Version 1.3
 *
 * This Demo class is a demonstration software (code) 
 * for my introduction to Java3D.
 */

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.NumberFormat;
import java.util.Enumeration;

import javax.media.j3d.Alpha;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.LineArray;
import javax.media.j3d.Locale;
import javax.media.j3d.Material;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PointLight;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.RotationInterpolator;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Switch;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.behaviors.picking.PickRotateBehavior;
import com.sun.j3d.utils.behaviors.picking.PickTranslateBehavior;
import com.sun.j3d.utils.behaviors.picking.PickZoomBehavior;
import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.geometry.Stripifier;
import com.sun.j3d.utils.image.TextureLoader;

/**
 * This class is the main class of the program Demo. It creates a Virtual
 * Universe and a Locale and attaches to the Locale: a right-handed 3D
 * coordinate system, a color cube, a tetrahedron, the earth and the ViewBranch.
 * It also overrides the addBranchGraph methode.
 */

public class Demo3D extends JFrame implements Runnable {
  static int screenwidth;

  static int screenheight;

  static Thread fpsThread;

  long sleepDuration = 200; // in msec

  int decimalForAllFps = 1;

  JLabel jLabel;

  // Create a virtual universe.
  VirtualUniverse universe = new VirtualUniverse();

  // A single hi-res. Locale node is created and attached to the
  // virtual universe.
  Locale locale = new Locale(universe);

  Canvas3D canvas3D;

  ViewBranch viewBr;

  /**
   * Constructor that allows to specify the desired initial instances.
   */
  public Demo3D() {
    // Set the best GraphicsConfiguration
    GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();

    GraphicsConfiguration graphConf = GraphicsEnvironment
        .getLocalGraphicsEnvironment().getDefaultScreenDevice()
        .getBestConfiguration(template);

    canvas3D = new Canvas3D(graphConf); // The used Canvas3D

    // Construction of the main frame.
    setTitle("Demo");

    JPanel jMainPanel = new JPanel(true);
    jMainPanel.setLayout(new BorderLayout(0, 5)); // hor_gap and ver_gap

    JPanel jFpsPanel = new JPanel(true);
    jFpsPanel.setBackground(Color.white);

    jLabel = new JLabel("");
    jLabel.setText("Wait for informations");
    jFpsPanel.add(jLabel);

    jMainPanel.add(canvas3D, BorderLayout.CENTER);

    /*
     * // For the stereo-mode with an "Head Monted Display" (HMD). JPanel
     * jScene_Stereo_Panel = new JPanel(true);
     * jScene_Stereo_Panel.setLayout(new GridLayout(1, 2, 0, 0)); // rows,
     * col, hor_gap and ver_gap jScene_Stereo_Panel.add(canvas3D);
     * jScene_Stereo_Panel.add(canvas3D);
     * jMainPanel.add(jScene_Stereo_Panel, BorderLayout.CENTER);
     */

    jMainPanel.add(jFpsPanel, BorderLayout.SOUTH);

    setContentPane(jMainPanel);

    // The ViewBranch class creates the instances of ViewPlatform, View,
    // etc.
    viewBr = new ViewBranch(canvas3D);

    fpsThread = new Thread(this);

    myScene();
  }

  /**
   * Assembling of all components of the scene.
   */
  public void myScene() {
    // Necessary to use NewTextureLoader in other classes.
    NewTextureLoader.setImageObserver(this); // AWT Component

    // Attach the subgraphs SceneBuilder1, SceneBuilder2, SceneBuilder3
    // and the ViewBranch to the Locale node.
    addBranchGraph(new SceneBuilder1().mySubGraph1());
    addBranchGraph(new SceneBuilder2().mySubGraph2());
    addBranchGraph(new SceneBuilder3(canvas3D).mySubGraph3());
    addBranchGraph(viewBr.myViewBranch());
  }

  /**
   * Allows to attach all subgraphs of the scene and the ViewBranch to the
   * Locale node.
   * 
   * @param javax.media.j3d.BranchGroup
   *            brGr - the root of the subgraph
   */

  public void addBranchGraph(BranchGroup brGr) {
    locale.addBranchGraph(brGr);
  }

  ///////////////////////////// Framemeter /////////////////////////////
  /**
   * This start method allows to start the thread of the framemeter.
   */
  public void start() {
    SwingUtilities.invokeLater(fpsThread);
  }

  /**
   * This run method allows to launch the computation of all frames per second
   * for the framemeter.
   */
  public void run() {
    long lastFrameTime;
    double fps;
    double min = Double.MAX_VALUE;
    double max = Double.MIN_VALUE;
    long count = 0;
    double sum = 0;
    double mean = 0;

    while (true) {
      lastFrameTime = viewBr.view.getLastFrameDuration();

      if (lastFrameTime > 0) {
        fps = 1000 / (double) lastFrameTime;
        count += 1;
        sum += fps;
        mean = sum / count;

        // To format all fps-informations.
        NumberFormat numbForm;
        numbForm = NumberFormat.getInstance();
        numbForm.setMaximumFractionDigits(decimalForAllFps);

        if (min > fps && fps != 0 && count > 4)
          min = fps;
        if (max < fps)
          max = fps;

        jLabel.setText("Frames/sec = " + numbForm.format(fps)
            + "  ;    minFrames/sec = " + numbForm.format(min)
            + "  ;    maxFrames/sec = " + numbForm.format(max)
            + "  ;    meanFrames/sec = " + numbForm.format(mean));

        // System.out.println("Frames per second = " + fps);
      }

      try {
        Thread.sleep(sleepDuration);
      } catch (InterruptedException e) {
      }
    }
  }

  ///////////////////////// End of the framemeter /////////////////////////

  /**
   * Main of the Demo program. Take the graphic environment of the
   * workstation.
   */
  public static void main(String args[]) {
    JFrame jFrameDemo = new Demo3D();

    // To be sure to stop the application when the frame is closed.
    WindowListener winListener = new WindowAdapter() {
      public void windowClosing(WindowEvent event) {
        System.exit(0);
      }
    };

    jFrameDemo.addWindowListener(winListener);

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    screenwidth = (int) screenSize.getWidth();
    screenheight = (int) screenSize.getHeight();
    jFrameDemo.setSize(screenwidth, screenheight);

    // Turn on the visibility of the frame.
    jFrameDemo.setVisible(true);

    fpsThread.start();
  }
}

/*
 * Author Claude G. Schwab Copyright (c) 2002 University of applied sciences
 * Biel School of Engineering and Architecture, Switzerland.
 * http://www.hta-bi.bfh.ch All Rights Reserved. Compiled with SDK 1.4.1 and
 * Java3D API Version 1.3
 * 
 * This ViewBranch class is a demonstration software (code) for my introduction
 * to Java3D.
 */

/**
 * This class creates all necessary objects on the "View Branch" side of the
 * scene graph.
 */

class ViewBranch {
  public BranchGroup vbBrGr;

  private Canvas3D canvas3D;

  private PhysicalBody body;

  private PhysicalEnvironment environment;

  public static View view; // static for the Framemeter

  private ViewPlatform viewPlat;

  private TransformGroup vpTrGrStart, vpTrGrKeys_Transl_Turn,
      vpTrGrKeys_Rot_Up_Down;

  private Transform3D trStart;

  private BoundingSphere cameraBounds;

  private Camera_Transl_Turn camera_Transl_Turn;

  private Camera_Rot_Up_Down camera_Rot_Up_Down;

  private Aimer aimer;

  /**
   * Constructor that allows to specify the desired Canvas3D.
   * 
   * @param javax.media.j3d.Canvas3D
   *            canv - the Canvas3D being used
   */
  public ViewBranch(Canvas3D canv) // The instance canv of Canvas3D class is
  { // created in the constructor of the Demo class.
    canvas3D = canv;
  }

  /**
   * Create the ViewBranch
   * 
   * @return javax.media.j3d.BranchGroup vbBrGr - the root of the ViewBranch
   */
  public BranchGroup myViewBranch() {
    // Create the minimal PhysicalBody and PhysicalEnvironnement
    // instances with default parameters.
    body = new PhysicalBody();
    environment = new PhysicalEnvironment();

    // Create a View instance and attach the Canvas3D, the PhysicalBody
    // and the PhysicalEnvironment to it.
    view = new View();
    view.setFrontClipDistance(0.02); // Default value is 0.1 m
    view.setBackClipDistance(40.0); // Default value is 10 m
    // Rem.: BackClipDistance / FrontClipDistance = 2000 > 1000 but < 3000
    view.addCanvas3D(canvas3D);
    view.setPhysicalBody(body);
    view.setPhysicalEnvironment(environment);
    /*
     * // Choices of the projection type. They are 2 possibilities, namely: //
     * PERSPECTIVE_PROJECTION and PARALLEL_PROJECTION. // Note: the default
     * value is PERSPECTIVE_PROJECTION
     * view.setProjectionPolicy(View.PARALLEL_PROJECTION);
     */
    // Create a ViewPlatform instance and bind it with the View instance.
    viewPlat = new ViewPlatform();
    viewPlat.setActivationRadius(40.0f); // Default value is 62 m
    view.attachViewPlatform(viewPlat);

    // Create the action volume for the camera's navigation.
    cameraBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

    // Create the two necessary TransformGroups for the ViewPlatform's
    // motion (6 translations and 4 rotations).
    vpTrGrKeys_Rot_Up_Down = new TransformGroup();
    vpTrGrKeys_Transl_Turn = new TransformGroup();

    // With the ALLOW_TRANSFORM_READ and ALLOW_TRANSFORM_WRITE
    // capabilities, we allow the modification of the TransformGroup's
    // code by the Behavior's code at run time.
    vpTrGrKeys_Transl_Turn
        .setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    vpTrGrKeys_Transl_Turn
        .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

    vpTrGrKeys_Rot_Up_Down
        .setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    vpTrGrKeys_Rot_Up_Down
        .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

    // Attach the ViewPlatform to the vpTrGrKeys_Rot_Up_Down node.
    vpTrGrKeys_Rot_Up_Down.addChild(viewPlat);

    // Create and attach an aimer to the TransformGroup node
    // vpTrGrKeys_Rot_Up_Down.
    aimer = new Aimer(1.5f);
    vpTrGrKeys_Rot_Up_Down.addChild(aimer.myAimer());

    // View-platform's motion ==> camera's navigation: 6 translations and 4
    // rotations.

    // Create and attach the camera's rotation on the vpTrGrKeys_Rot_Up_Down
    // node.
    camera_Rot_Up_Down = new Camera_Rot_Up_Down(vpTrGrKeys_Rot_Up_Down);
    camera_Rot_Up_Down.setSchedulingBounds(cameraBounds);
    vpTrGrKeys_Rot_Up_Down.addChild(camera_Rot_Up_Down);

    // Create and attach the camera's translation and rotation instances
    // on the vpTrGrKeys_Transl_Turn node.
    camera_Transl_Turn = new Camera_Transl_Turn(vpTrGrKeys_Transl_Turn);
    camera_Transl_Turn.setSchedulingBounds(cameraBounds);
    vpTrGrKeys_Transl_Turn.addChild(camera_Transl_Turn);

    // Attach the vpTrGrKeys_Rot_Up_Down node to the vpTrGrKeys_Transl_Turn
    // node.
    vpTrGrKeys_Transl_Turn.addChild(vpTrGrKeys_Rot_Up_Down);

    // Give the starting position of the ViewPlatform.
    trStart = new Transform3D(); // Identity matrix
    trStart.set(new Vector3f(0.0f, 0.0f, 10.0f)); // Translation of the
    // camera (0,0,10)

    // Create the TransformGroup node for the ViewPlatform's
    // starting position.
    vpTrGrStart = new TransformGroup(trStart);

    // Attach the vpTrGrKeys_Transl_Turn node to the TransformGroup
    // node vpTrGrStart.
    vpTrGrStart.addChild(vpTrGrKeys_Transl_Turn);

    // Add the TransformGroup node vpTrGrStart to the view
    // BranchGroup node vbBrGr.
    vbBrGr = new BranchGroup();
    vbBrGr.addChild(vpTrGrStart);

    // Compile the ViewBranch to optimize the performances.
    vbBrGr.compile();

    // Return the final version of the view branch BranchGroup node vbBrGr.
    return vbBrGr;
  }
}

/**
 * This class serves to put a locale right-handed 3D coordinate system as
 * reference system into the scene. It also creates a background, the
 * illumination of the scene and the borders of the virtual universe.
 */

class SceneBuilder1 {
  public BranchGroup brGr1;

  private CoordSyst coordSyst;

  private BoundingSphere boundsBackGr, boundsGen;

  private Background backGr;

  private NewTextureLoader newTextureLoader;

  private AmbientLight ambientLight;

  private PointLight pointLight;

  private DirectionalLight directionalLight;

  private BordersIn bordersIn;

  private BordersOut bordersOut;

  private static final float dimUniverse = 5.0f; // dimensions of the virtual

  // universe are:

  // dimUniverse x dimUniverse x dimUniverse

  /**
   * Create the subgraph #1
   * 
   * @return javax.media.j3d.BranchGroup brGr1 - the root of the subgraph #1
   */
  public BranchGroup mySubGraph1() {
    // Create the BranchGroup brGr1 of the subgraph #1.
    brGr1 = new BranchGroup();

    // Create and attach the coordinate system to the brGr1.
    coordSyst = new CoordSyst(1.0f, 1.0f, 0.0f, // Color of the x-axis
        0.0f, 0.0f, 1.0f, // Color of the y-axis
        1.0f, 0.0f, 0.0f, // Color of the z-axis
        0.75f); // Lenght of the 3 axes
    brGr1.addChild(coordSyst);

    // Background setting for the scene.
    newTextureLoader = new NewTextureLoader("Images/Ciel_Out.jpg");
    newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
    backGr = new Background(newTextureLoader.getImage());
    backGr.setImageScaleMode(Background.SCALE_FIT_ALL);
    boundsBackGr = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 1000.0);
    backGr.setApplicationBounds(boundsBackGr);
    brGr1.addChild(backGr);

    // A BoundingSphere instance as general bounding region.
    boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

    // Lighting of the scene.

    // Create and attach an ambient light.
    ambientLight = new AmbientLight(true, new Color3f(0.2f, 0.2f, 0.2f));
    ambientLight.setInfluencingBounds(boundsGen);
    brGr1.addChild(ambientLight);

    // Create and attach a point light.
    pointLight = new PointLight(true, new Color3f(1.0f, 1.0f, 0.3f),
        new Point3f(-100.0f, 0.0f, 100.0f), new Point3f(0.0f, 0.05f,
            0.1f));
    pointLight.setInfluencingBounds(boundsGen);
    brGr1.addChild(pointLight);

    // Create and attach a directional light.
    directionalLight = new DirectionalLight(true, new Color3f(0.8f, 1.0f,
        1.0f), new Vector3f(-0.5f, -0.5f, -0.5f));
    directionalLight.setInfluencingBounds(boundsGen);
    brGr1.addChild(directionalLight);

    // Create the borders of the virtual universe for the inside view of the
    // scene.
    bordersIn = new BordersIn(dimUniverse);
    brGr1.addChild(bordersIn.myInternalUniverse());

    // Create the borders of the virtual universe for the outside view of
    // the scene.
    bordersOut = new BordersOut(dimUniverse);
    brGr1.addChild(bordersOut.myExternalUniverse());

    // Compile the subgraph to optimize the performances.
    brGr1.compile();

    // Return the final version of the BranchGroup node brGr1
    return brGr1;
  }
}

/**
 * This class serves to put a colored cube into the scene graph. It also
 * produces a "static rotation" and a "dynamic rotation" of the colored cube.
 */

class SceneBuilder2 {
  public BranchGroup brGr2;

  private BoundingSphere boundsGen;

  private TransformGroup trGr2_1, trGr2_2;

  private CoordSyst coordSyst;

  private ColorCube colorCube;

  private Transform3D trans1, rot1;

  private Alpha rotationAlpha;

  private AxisAngle4f axe_rot;

  private RotationInterpolator rotator;

  /**
   * Create the subgraph #2
   * 
   * @return javax.media.j3d.BranchGroup brGr2 - the root of the subgraph #2
   */
  public BranchGroup mySubGraph2() {
    // Create the BranchGroup node brGr2 of the second subgraph.
    brGr2 = new BranchGroup();

    // A BoundingSphere instance as general bounding region.
    boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

    // Create a Transform3D instance rot1 to perform the necessary
    // "static rotation" for the desired cube's position.
    rot1 = new Transform3D();

    // Rotation of Pi/2 - arctan(1/sqrt(2)) = 0.955 rad about the
    // (1,0,-1)-axis passing through the origin.
    axe_rot = new AxisAngle4f(1.0f, 0.0f, -1.0f, 0.955f);
    rot1.setRotation(axe_rot);

    // Create the first TransformGroup node trGr2_1 and attach the
    // "static rotation" rot1 instance to it.
    trGr2_1 = new TransformGroup(rot1);

    // Create and attach a coordinate system to the TransformGroup node
    // trGr2_1 of the subgraph #2, that is to the cube.
    coordSyst = new CoordSyst(1.0f, 1.0f, 0.0f, // Color of the x-axis
        0.0f, 0.0f, 1.0f, // Color of the y-axis
        1.0f, 0.0f, 0.0f, // Color of the z-axis
        0.4f); // Lenght of the 3 axes
    trGr2_1.addChild(coordSyst);

    // Create the ColorCube (Shape3D) and attach it to the
    // TransformGroup node trGr2_1 of the subgraph #2.
    colorCube = new ColorCube(0.5f);
    trGr2_1.addChild(colorCube);

    // Create the second TransformGroup node trGr2_2.
    trGr2_2 = new TransformGroup();

    // With the ALLOW_TRANSFORM_WRITE capability, we allow the
    // modification of the TransformGroup's code by the behavior's
    // code at run time.
    trGr2_2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

    // Attach the first node trGr2_1 to the second node trGr2_2.
    trGr2_2.addChild(trGr2_1);

    // Prepare the RotationInterpolator (Behavior) for the
    // cube's rotation about the y-axis.
    trans1 = new Transform3D();

    // Create the alpha(t) function.
    rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 10000, 0,
        0, 0, 0, 0);
    // Create the cube's rotation about the y-axis.
    rotator = new RotationInterpolator(rotationAlpha, trGr2_2, trans1,
        0.0f, (float) Math.PI * 2.0f);
    rotator.setSchedulingBounds(boundsGen);

    trGr2_2.addChild(rotator);

    brGr2.addChild(trGr2_2);

    // Compile the subgraph to optimize the performances.
    brGr2.compile();

    // Return the final version of the BranchGroup node brGr2
    return brGr2;
  }
}

/**
 * This class serves to attache both the BranchGraph31 and BranchGraph32 to the
 * Locale and to pick the tetrahedron.
 */

/*
 * Note: It is not always necessary to use "detach" and "add" to add/remove a
 * subgraph from a scene graph. In many cases the using of the setEnable()
 * method, to turn a subgraph on and off, is adequate.
 */

class SceneBuilder3 {
  public BranchGroup brGr3;

  private AddDetachEarthBehavior addDetachEarthBehavior;

  private BoundingSphere boundsGen, pickBounds;

  private Canvas3D canvas3D; // needed 3 times for the Picking of the

  // tetrahedron

  private PickRotateBehavior pickRotBehavior;

  private PickZoomBehavior pickZoomBehavior;

  private PickTranslateBehavior pickTransBehavior;

  private SceneBuilder31 sceneBuilder31;

  private SceneBuilder32 sceneBuilder32;

  private Tetrahedron tetrahedron;

  /**
   * Constructor that allows to specify the desired Canvas3D.
   * 
   * @param javax.media.j3d.Canvas3D
   *            canv - the active Canvas3D
   */
  public SceneBuilder3(Canvas3D canv) {
    canvas3D = canv;
  }

  /**
   * Create the subgraph #3
   * 
   * @return javax.media.j3d.BranchGroup brGr3 - the root of the subgraph #3
   */
  public BranchGroup mySubGraph3() {
    // Create the BranchGroup node brGr3, in other words the root of
    // the subgraph31 and subgraph32.
    brGr3 = new BranchGroup();

    // To allow the detach/add process of the subgraph 32 from the
    // BranchGroup node brGr3.
    brGr3.setCapability(Group.ALLOW_CHILDREN_READ);
    brGr3.setCapability(Group.ALLOW_CHILDREN_WRITE);
    brGr3.setCapability(Group.ALLOW_CHILDREN_EXTEND);

    // A BoundingSphere instance as picking bound region.
    pickBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 5.0);

    // A BoundingSphere instance as general bounding region.
    boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

    // Create and attach the subgraph31 with the tetrahedron
    // to the BranchGroup node brGr3.
    tetrahedron = new Tetrahedron(1.0f);
    sceneBuilder31 = new SceneBuilder31(tetrahedron.myTetrahedron());
    brGr3.addChild(sceneBuilder31.mySubGraph31());

    // Picking of the tetrahedron
    // Note:It's the instruction:
    //      trGr31.setCapability(TransformGroup.ENABLE_PICK_REPORTING)
    //      in the class SceneBuilder31 that determines if the
    //      tetrahedron is pickable or not.

    // Pick and translate the tetrahedron parallel to the z-axis if the
    // mouse pointer is over it.
    pickZoomBehavior = new PickZoomBehavior(brGr3, canvas3D, pickBounds);
    // pickZoomBehavior.setEnable(ctrlDown);
    brGr3.addChild(pickZoomBehavior);

    // Pick and translate the tetrahedron in the (x-y)-plane if the
    // mouse pointer is over it.
    pickTransBehavior = new PickTranslateBehavior(brGr3, canvas3D,
        pickBounds);
    // pickTransBehavior.setEnable(ctrlDown);
    brGr3.addChild(pickTransBehavior);

    // Pick and rotate the tetrahedron if the mouse pointer is over it.
    pickRotBehavior = new PickRotateBehavior(brGr3, canvas3D, pickBounds);
    // pickRotBehavior.setEnable(ctrlDown);
    brGr3.addChild(pickRotBehavior);

    // Create the subgraph32 ===> the earth in double rotation.
    sceneBuilder32 = new SceneBuilder32();
    brGr3.addChild(sceneBuilder32.mySubGraph32());

    // Create an instance of the AddDetachEarthBehavior class to
    // allow the detach/add process of the subgraph32.
    addDetachEarthBehavior = new AddDetachEarthBehavior(this,
        sceneBuilder32);
    addDetachEarthBehavior.setSchedulingBounds(boundsGen);
    brGr3.addChild(addDetachEarthBehavior);

    // Compile the subgraph to optimize the performances.
    brGr3.compile();

    // Return the final version of the BranchGroup node brGr3
    return brGr3;
  }

  /**
   * This method is called up in the DetachEathBehavior class to add a new
   * representation of the earth.
   */
  public void addEarth() {
    brGr3.addChild(sceneBuilder32.mySubGraph32());
  }
}

/**
 * This class serves to put the objet (a tetrahedron) into the scene. It also
 * produces a "static translation" of the tetrahedron and allows its picking.
 */

class SceneBuilder31 {
  public TransformGroup trGr31;

  private Shape3D myObject;

  private Transform3D transl;

  private Vector3d vectransl; // translation

  /**
   * Constructor that allows to specify the desired object.
   * 
   * @param javax.media.j3d.Shape3D
   *            objet - the Shape3D instance which will be attached to the
   *            subgraph #31
   */
  public SceneBuilder31(Shape3D object) {
    myObject = object;
  }

  /**
   * Create the subgraph #31 and prepare the TransformGroup node trGr31 for
   * the tetrahedron's picking.
   * 
   * @return javax.media.j3d.TransformGroup trGr31_2 - the root of the
   *         subgraph #31
   */
  public TransformGroup mySubGraph31() {
    // Create a Transform3D node to execute the desired "static translation"
    // of the tetrahedron ===> start position.
    transl = new Transform3D();
    vectransl = new Vector3d(0.0, -2.0, 0.0); // translation
    transl.set(vectransl);

    // Create the TransformGroup node trGr31, attach into it the "static
    // translation" instance and prepare it for the picking.
    trGr31 = new TransformGroup(transl);
    trGr31.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    trGr31.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    trGr31.setCapability(TransformGroup.ENABLE_PICK_REPORTING);

    // Attach myObject (Shape3D leaf) to the TransformGroup node trGr31.
    trGr31.addChild(myObject);

    // Return the final version of the TransformGroup node trGr31.
    return trGr31;
  }
}

/**
 * This class serves to put the rendering of five different earth's
 * representations (each with a right-handed 3D coordinate system) into the
 * scene graph. It also produces a "static translation" and a double "dynamic
 * rotation" of each earth's representations and allows to detach and then add
 * again this subgraph32 from to the entire scene graph.
 */

/*
 * Note: It is not always necessary to use "detach" and "add" to detach/add a
 * subgraph from a scene graph. In many cases the using of the setEnable()
 * method, to turn a subgraph on and off, is adequate.
 */

class SceneBuilder32 {
  public BranchGroup brGr32;

  private TransformGroup trGr32_1, trGr32_2, trGr32_3;

  private int thisEarth;

  private BoundingSphere boundsGen;

  private CoordSyst coordSyst;

  private SwitchBehavior switchBehavior;

  private Switch switchEarths; // the Switch for the 5 different earth's

  // representations

  private Transform3D transl;

  private Vector3d vectTransl; // translation

  private Alpha rotationAlpha_1, rotationAlpha_2;

  private RotationInterpolator rotator_1, rotator_2;

  // The five different earth's representations
  private Earth earth_Points, earth_Lines, earth_Polygons, earth_Gouraud,
      earth_Texture;

  /**
   * Create the subgraph #32
   * 
   * @return javax.media.j3d.TransformGroup trGr32_3 - the root of the
   *         subgraph #32
   */
  public BranchGroup mySubGraph32() {
    // A BoundingSphere instance as general bounding region.
    boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

    // Create the first TransformGroup node trGr32_1 to:
    // 1) attach the Switch node with the five different earth's
    //    representations to the subgraph32
    // 2) attach a coordinate system to each earth's representation
    // 3) rotate each earth about its own y-axis.
    trGr32_1 = new TransformGroup();

    // With the ALLOW_TRANSFORM_WRITE capability, we allow the
    // modification of the TransformGroup's code by the behavior's
    // code at run time.
    trGr32_1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

    // SwitchBehavior is the class which controls the fonctioning of
    // the switchEarths node.

    switchBehavior = new SwitchBehavior(this);
    switchBehavior.setSchedulingBounds(boundsGen);
    trGr32_1.addChild(switchBehavior);

    // The Switch which allows the rendering of the five different
    // earth's representations.
    switchEarths = new Switch();
    // With the ALLOW_TRANSFORM_WRITE, ALLOW_SWITCH_WRITE and
    // ALLOW_CHILDREN_READ
    // capabilities we allow to get or set new capabilities.
    switchEarths.setCapability(Switch.ALLOW_SWITCH_READ);
    switchEarths.setCapability(Switch.ALLOW_SWITCH_WRITE);
    switchEarths.setCapability(Switch.ALLOW_CHILDREN_READ);

    // Attach the different earth's representations to the Switch node.
    // Increasing
    earth_Points = new Earth("points", 0.4f);
    switchEarths.addChild(earth_Points.myEarth()); // # 0

    earth_Lines = new Earth("lines", 0.4f);
    switchEarths.addChild(earth_Lines.myEarth()); // # 1

    earth_Polygons = new Earth("polygons", 0.4f);
    switchEarths.addChild(earth_Polygons.myEarth()); // # 2

    earth_Gouraud = new Earth("gouraud", 0.4f);
    switchEarths.addChild(earth_Gouraud.myEarth()); // # 3

    earth_Texture = new Earth("texture", 0.4f);
    switchEarths.addChild(earth_Texture.myEarth()); // # 4

    // Decreasing
    switchEarths.addChild(earth_Texture.myEarth()); // # 4
    switchEarths.addChild(earth_Gouraud.myEarth()); // # 3
    switchEarths.addChild(earth_Polygons.myEarth()); // # 2
    switchEarths.addChild(earth_Lines.myEarth()); // # 1
    switchEarths.addChild(earth_Points.myEarth()); // # 0

    // Attach the Switch node with the five different earth's
    // representations to the TransformGroup node trGr32_1.
    trGr32_1.addChild(switchEarths);

    // Create and attach a coordinate system to the TransformGroup node
    // trGr32_1, that is to each earth's representation.
    coordSyst = new CoordSyst(1.0f, 1.0f, 0.0f, // Color of the x-axis
        0.0f, 0.0f, 1.0f, // Color of the y-axis
        1.0f, 0.0f, 0.0f, // Color of the z-axis
        0.6f); // Lenght of the 3 axes
    trGr32_1.addChild(coordSyst);

    // Create the alpha(t) function for the earth's rotation about
    // its own y-axis.
    rotationAlpha_1 = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 10000,
        0, 0, 0, 0, 0);
    // Create the earth's rotation about its own y-axis.
    rotator_1 = new RotationInterpolator(rotationAlpha_1, trGr32_1,
        new Transform3D(), 0.0f, (float) Math.PI * 2.0f);
    rotator_1.setSchedulingBounds(boundsGen);
    trGr32_1.addChild(rotator_1);

    // Create a Transform3D instance to execute the desired "static
    // translation" of the earth, that is the rotation radius around
    // the sun.
    transl = new Transform3D();
    vectTransl = new Vector3d(2.5, 0.0, 0.0);
    transl.set(vectTransl);

    // Create the second TransformGroup node trGr32_2 and attach the
    // "static translation" transl to it.
    trGr32_2 = new TransformGroup(transl);

    // Attach the trGr32_1 node to the trGr32_2 node.
    trGr32_2.addChild(trGr32_1);

    // Create the third TransformGroup node trGr32_3 for the earth's
    // rotation around the sun.
    trGr32_3 = new TransformGroup();

    // With the ALLOW_TRANSFORM_WRITE capability, we allow the
    // modification of the TransformGroup's code by the behavior's
    // code at run time.
    trGr32_3.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

    // Attach the trGr32_2 node to the trGr32_3 node.
    trGr32_3.addChild(trGr32_2);

    // Create the alpha(t) function for the earth's rotation around the sun.
    rotationAlpha_2 = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 20000,
        0, 0, 0, 0, 0);

    // To restart correctly the rotation of the earth around the
    // sun after a detach/add process of the subgraph32 from the
    // BranchGroup node brGr3.
    rotationAlpha_2.setStartTime(System.currentTimeMillis());

    // Create the earth's rotation around the sun.
    rotator_2 = new RotationInterpolator(rotationAlpha_2, trGr32_3,
        new Transform3D(), 0.0f, (float) Math.PI * 2.0f);
    rotator_2.setSchedulingBounds(boundsGen);
    trGr32_3.addChild(rotator_2);

    // To allow the detaching of this subgraph32 from the
    // BranchGroup node brGr3.
    brGr32 = new BranchGroup();
    brGr32.setCapability(BranchGroup.ALLOW_DETACH);
    brGr32.addChild(trGr32_3);

    // Return the final version of the BranchGroup node brGr32.
    return brGr32;
  }

  /**
   * This method is called up in the SwitchBehavior class and gets the new
   * earth's representation which has to be drawn.
   * 
   * @param thisEarth -
   *            the new earth's representation to draw.
   */
  public void setNewEarth(int thisEarth) {
    switchEarths.setWhichChild(thisEarth);
  }

  // This method is called up in the DetachEathBehavior class to
  // detach the momentary representation of the earth.
  public void detachEarth() {
    brGr32.detach();
  }
}
/*
 * @(#)NewTextureLoades.java 1.0 99/10/21
 * 
 * Copyright (c) 1996-1999 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.
 */

/**
 * A texture loading utility that doesn't require an image observer for
 * constructing objects. This class extends the TextureLoader class of the
 * com.sun.j3d.utils.image package.
 *  
 */

class NewTextureLoader extends TextureLoader {
  static java.awt.Component observer;

  /**
   * Specify an object to server as the image observer. Use this method once
   * before constructing any texture loaders.
   * 
   * @param imageObserver
   *            the object to be used in subsequent NewTextureLoader
   *            constuctions
   */
  public static void setImageObserver(java.awt.Component imageObserver) {
    observer = imageObserver;
  }

  /**
   * Retreve the object used as the image observer for NewTextureLoader
   * objects. Use this method when the image observer is needed.
   * 
   * @return the object used in as the image observer in subsequent
   *         NewTextureLoader constuctions
   */
  public static java.awt.Component getImageObserver() {
    return observer;
  }

  // constructors without an image observer argument
  /**
   * Constructs a NewTextureLoader object loading the specified iamge in
   * default (RGBA) format. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param image
   *            the image object to load
   */
  public NewTextureLoader(java.awt.Image image) {
    super(image, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified image and
   * option flags in the default (RGBA) format. The an image observer must be
   * set using the setImageObserver() method before using this constructor.
   * 
   * @param image
   *            the image object to load
   * @param flags
   *            the flags to use in construction (e.g. generate mipmap)
   */
  public NewTextureLoader(java.awt.Image image, int flags) {
    super(image, flags, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified file using the
   * specified format. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param image
   *            the image object to load
   * @param format
   *            specificaiton of which channels to use (e.g. RGB)
   */
  public NewTextureLoader(java.awt.Image image, java.lang.String format) {
    super(image, format, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified file with
   * specified format and flags. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param image
   *            the image object to load
   * @param format
   *            specificaiton of which channels to use (e.g. RGB)
   * @param flags
   *            the flags to use in construction (e.g. generate mipmap)
   */
  public NewTextureLoader(java.awt.Image image, java.lang.String format,
      int flags) {
    super(image, format, flags, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified file using the
   * default format (RGBA). The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param fname
   *            the name of the file to load
   */
  public NewTextureLoader(java.lang.String fname) {
    super(fname, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified file with the
   * specified flags. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param fname
   *            the name of the file to load
   * @param flags
   *            the flags to use in construction (e.g. generate mipmap)
   */
  public NewTextureLoader(java.lang.String fname, int flags) {
    super(fname, flags, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified file using the
   * specified format. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param fname
   *            the name of the file to load
   * @param format
   *            specificaiton of which channels to use (e.g. RGB)
   */
  public NewTextureLoader(java.lang.String fname, java.lang.String format) {
    super(fname, format, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified file using the
   * specified format and flags. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param fname
   *            the name of the file to load
   * @param format
   *            specificaiton of which channels to use (e.g. RGB)
   * @param flags
   *            the flags to use in construction (e.g. generate mipmap)
   */
  public NewTextureLoader(java.lang.String fname, java.lang.String format,
      int flags) {
    super(fname, format, flags, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified URL using the
   * default format. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param url
   *            specifies the URL of the image to load
   */
  public NewTextureLoader(java.net.URL url) {
    super(url, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified URL using the
   * specified flags. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param url
   *            specifies the URL of the image to load
   * @param flags
   *            the flags to use in construction (e.g. generate mipmap)
   */
  public NewTextureLoader(java.net.URL url, int flags) {
    super(url, flags, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified URL using the
   * specified format. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param url
   *            specifies the URL of the image to load
   * @param format
   *            specificaiton of which channels to use (e.g. RGB)
   */
  public NewTextureLoader(java.net.URL url, java.lang.String format) {
    super(url, format, observer);
  }

  /**
   * Constructs a NewTextureLoader object loading the specified URL using the
   * specified format and flags. The an image observer must be set using the
   * setImageObserver() method before using this constructor.
   * 
   * @param url
   *            specifies the URL of the image to load
   * @param format
   *            specificaiton of which channels to use (e.g. RGB)
   * @param flags
   *            the flags to use in construction (e.g. generate mipmap)
   */
  public NewTextureLoader(java.net.URL url, java.lang.String format, int flags) {
    super(url, format, flags, observer);
  }

} // end of TexturedPlane class

/**
 * This class is a keyboard behavior to control the partly rotation (rotate up
 * and rotate down) of the camera.
 */

class Camera_Rot_Up_Down extends Behavior {
  // The TransformGroup node to modify by the keyboard interaction.
  private TransformGroup target_trGr;

  // Wake up event when a key is pressed.
  private WakeupOnAWTEvent wakeUp = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);

  // The key event
  private KeyEvent keyEvent;

  // The angle to turn when the Home key or End key is pressed.
  private float angle = (float) Math.PI / 36;

  private Transform3D myKeyNavTransf3D = new Transform3D();

  private Transform3D rotation = new Transform3D();

  /**
   * Constructor that allows to specify the desired target transform group.
   * 
   * @param javax.media.j3d.TransformGroup
   *            target - the target transform group
   */
  public Camera_Rot_Up_Down(TransformGroup target) {
    target_trGr = target;
  }

  /**
   * Override Behavior's initialize method to setup wakeup criteria.
   */
  public void initialize() {
    wakeupOn(wakeUp);
  }

  /**
   * Override Behavior's stimulus method to handle the event. This method is
   * called when a key on the keyboard has been pressed and operates on the
   * specified transform group to move the camera.
   * 
   * @param Enumeration
   *            criteria - all pressed keys in a list. This will be passed by
   *            the system.
   */
  public void processStimulus(Enumeration criteria) {
    WakeupOnAWTEvent eventToWakeUp;
    AWTEvent[] events;

    if (criteria.hasMoreElements()) {
      // Decode the wakeup criteria
      eventToWakeUp = (WakeupOnAWTEvent) criteria.nextElement();
      events = eventToWakeUp.getAWTEvent();
      keyEvent = (KeyEvent) events[0];
      int keyCode = keyEvent.getKeyCode();

      // Perform our processing

      // Get the initial transformation from target and put it
      // into myKeyNavTransf3D
      target_trGr.getTransform(myKeyNavTransf3D);

      // Not any of the 2 rotations don't act simultaneously.
      switch (keyCode) {
      case KeyEvent.VK_HOME: // Home - rotate up
        rotation.rotX(angle);
        break;

      case KeyEvent.VK_END: // End - rotate down
        rotation.rotX(-angle);
        break;

      default:
        rotation.rotX(0.0f);
      }

      myKeyNavTransf3D.mul(rotation);

      // Return the final transformation myKeyNavTransf3D to target
      target_trGr.setTransform(myKeyNavTransf3D);
    }

    // Set wakeup criteria for next time.
    wakeupOn(wakeUp);
  }
}

/**
 * This class creates an aimer in the ViewBranch.
 */

class Aimer extends Shape3D {
  private float scale_XYZ;

  private LineArray aimer;

  private float scaledExtremites[];

  /**
   * Constructor that allows to specify the desired initial aimer's
   * dimensions.
   * 
   * @param type
   *            float s_XYZ - the scale factor to adjust the aimer's
   *            dimensions
   */
  public Aimer(float s_XYZ) {
    scale_XYZ = s_XYZ;
  }

  /**
   * Construct an aimer.
   * 
   * @return javax.media.j3d.Shape3D myAimer - the constructed aimer.
   */
  public Shape3D myAimer() {
    // Construction of the aimer (LineArray).
    aimer = new LineArray(20, LineArray.COORDINATES | LineArray.COLOR_3);

    // Scalling of the vertices of the aimer using scale_XYZ.
    scaledExtremites = new float[extremites.length];
    for (int i = 0; i < extremites.length; i++)
      scaledExtremites[i] = extremites[i] * scale_XYZ;

    aimer.setCoordinates(0, scaledExtremites);
    aimer.setColors(0, color);

    this.setGeometry(aimer);

    return this;
  }

  // Aimer's geometry
  private static final float extremites[] = {
  // top-front
      0.075f, 0.05f, -1.0f, -0.075f, 0.05f, -1.0f,

      // left-front
      -0.075f, 0.05f, -1.0f, -0.075f, -0.05f, -1.0f,

      // bottom-front
      -0.075f, -0.05f, -1.0f, 0.075f, -0.05f, -1.0f,

      // right-front
      0.075f, -0.05f, -1.0f, 0.075f, 0.05f, -1.0f,

      // top-back
      0.04f, 0.025f, -1.0f, -0.04f, 0.025f, -1.0f,

      // left-back
      -0.04f, 0.025f, -1.0f, -0.04f, -0.025f, -1.0f,

      // bottom-back
      -0.04f, -0.025f, -1.0f, 0.04f, -0.025f, -1.0f,

      // right-back
      0.04f, -0.025f, -1.0f, 0.04f, 0.025f, -1.0f,

      // cross
      -0.04f, 0.025f, -1.0f, 0.04f, -0.025f, -1.0f, -0.04f, -0.025f,
      -1.0f, 0.04f, 0.025f, -1.0f };

  // Colors of the aimer (each vertex in aimer is red).
  float color[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // front-frame
      1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
      0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

      1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // back-frame
      1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
      0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

      1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // cross
      1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
}

/**
 * This class creates a simple cube with a given texture to simulate the inside
 * of the virtual universe.
 */

class BordersIn extends Shape3D {
  private QuadArray cube;

  private float scale_XYZ;

  private NewTextureLoader newTextureLoader;

  private Texture texture;

  private TextureAttributes textAttr;

  /**
   * Constructor that allows to specify the desired scale factor of the
   * virtual universe.
   * 
   * @param type
   *            float s_XYZ - the scale factor to adjust the borders of the
   *            virtual universe
   */
  public BordersIn(float s_XYZ) {
    scale_XYZ = s_XYZ;
  }

  /**
   * Construction of the desired borders of the virtual universe (cube).
   * 
   * @return javax.media.j3d.Shape3D myUniverse - the constructed borders of
   *         the virtual universe
   */
  public Shape3D myInternalUniverse() {
    cube = new QuadArray(cubeFaces.length, QuadArray.COORDINATES
        | QuadArray.TEXTURE_COORDINATE_2);

    ////////////////////// Geometric part ///////////////////////////

    // Scaling of the faces.
    for (int i = 0; i < cubeFaces.length; i++)
      cubeFaces[i].scale(scale_XYZ);

    cube.setCoordinates(0, cubeFaces);

    for (int i = 0; i < cubeFaces.length; i++) {
      // With i mod 4 ==> 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 for
      // the 4 vertices of the 6 faces, thus each vertex has
      // a point in the texture space. In this case, each cube's
      // face has the same texture coordinates.
      cube.setTextureCoordinate(0, i, textCoord[i % 4]);
    }

    // The geometry is passed to the instance this of the cube.
    this.setGeometry(cube);

    ////////////////////// Appearance part ///////////////////////////

    Appearance appearance = new Appearance();

    // This code block is only necessary to insure, in all cases, the
    // correct
    // rendering of the 6 faces of the cube (bug in Java3D version 1.2.0 !).
    // Set up the polygon's rendering-mode
    PolygonAttributes polygonAttributes = new PolygonAttributes();
    polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL);
    appearance.setPolygonAttributes(polygonAttributes);

    // Loading the texture for the 6 cube's faces.
    newTextureLoader = new NewTextureLoader("Images/Galaxies.gif");
    newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
    texture = newTextureLoader.getTexture();
    appearance.setTexture(texture);

    // Application modes of the texture
    textAttr = new TextureAttributes();
    textAttr.setTextureMode(TextureAttributes.MODULATE); // there still are:
    // BLEND, COMBINE,
    // DECAL, and REPLACE
    appearance.setTextureAttributes(textAttr);

    // The appearance is passed to the instance this of the cube.
    this.setAppearance(appearance);

    return this;
  }

  // The 8 vertices p1, p2, ..., p8 of the cube.
  private static final Point3f p1 = new Point3f(1.0f, 1.0f, 1.0f);

  private static final Point3f p2 = new Point3f(1.0f, -1.0f, 1.0f);

  private static final Point3f p3 = new Point3f(-1.0f, -1.0f, 1.0f);

  private static final Point3f p4 = new Point3f(-1.0f, 1.0f, 1.0f);

  private static final Point3f p5 = new Point3f(-1.0f, 1.0f, -1.0f);

  private static final Point3f p6 = new Point3f(-1.0f, -1.0f, -1.0f);

  private static final Point3f p7 = new Point3f(1.0f, -1.0f, -1.0f);

  private static final Point3f p8 = new Point3f(1.0f, 1.0f, -1.0f);

  // The 6 faces of the cube.
  private static final Point3f cubeFaces[] = { // internal front face
  p5, p6, p7, p8,

  // internal right face
      p1, p8, p7, p2,

      // internal back face
      p1, p2, p3, p4,

      // internal left face
      p4, p3, p6, p5,

      // internal top face
      p1, p4, p5, p8,

      // internal bottom face
      p3, p2, p7, p6 };

  // Coordinates in the texture space. Each cube's face has the
  // same texture coordinates.
  private TexCoord2f textCoord[] = { new TexCoord2f(0.0f, 0.0f),
      new TexCoord2f(0.0f, 1.0f), new TexCoord2f(1.0f, 1.0f),
      new TexCoord2f(1.0f, 0.0f) };
}

/**
 * This class creates a simple cube with a given texture to simulate the outside
 * of the virtual universe.
 */

class BordersOut extends Shape3D {
  private QuadArray cube;

  private float scale_XYZ;

  private NewTextureLoader newTextureLoader;

  private Texture texture;

  private TextureAttributes textAttr;

  /**
   * Constructor that allows to specify the desired scale factor of the
   * virtual universe.
   * 
   * @param type
   *            float s_XYZ - the scale factor to adjust the borders of the
   *            virtual universe
   */
  public BordersOut(float s_XYZ) {
    scale_XYZ = s_XYZ;
  }

  /**
   * Construction of the desired borders of the virtual universe (cube).
   * 
   * @return javax.media.j3d.Shape3D myUniverse - the constructed borders of
   *         the virtual universe
   */
  public Shape3D myExternalUniverse() {
    cube = new QuadArray(cubeFaces.length, QuadArray.COORDINATES
        | QuadArray.TEXTURE_COORDINATE_2);

    ////////////////////// Geometric part ///////////////////////////

    // Scaling of the faces.
    for (int i = 0; i < cubeFaces.length; i++)
      cubeFaces[i].scale(scale_XYZ);

    cube.setCoordinates(0, cubeFaces);

    for (int i = 0; i < cubeFaces.length; i++) {
      // With i mod 4 ==> 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 for
      // the 4 vertices of the 6 faces, thus each vertex has
      // a point in the texture space. In this case, each cube's
      // face has the same texture coordinates.
      cube.setTextureCoordinate(0, i, textCoord[i % 4]);
    }

    // The geometry is passed to the instance this of the cube.
    this.setGeometry(cube);

    ////////////////////// Appearance part ///////////////////////////

    Appearance appearance = new Appearance();

    // This code block is only necessary to insure, in all cases, the
    // correct
    // rendering of the 6 faces of the cube (bug in Java3D version 1.2.0 !).
    // Set up the polygon's rendering-mode
    PolygonAttributes polygonAttributes = new PolygonAttributes();
    polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL);
    appearance.setPolygonAttributes(polygonAttributes);

    // Loading the texture for the 6 cube's faces.
    newTextureLoader = new NewTextureLoader("Images/Ciel_Outside.jpg");
    newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
    texture = newTextureLoader.getTexture();
    appearance.setTexture(texture);

    // Application modes of the texture
    textAttr = new TextureAttributes();
    textAttr.setTextureMode(TextureAttributes.MODULATE); // there still are:
    // BLEND, COMBINE,
    // DECAL, and REPLACE
    appearance.setTextureAttributes(textAttr);

    // The appearance is passed to the instance this of the cube.
    this.setAppearance(appearance);

    return this;
  }

  // The 8 vertices p1, p2, ..., p8 of the cube.
  private static final Point3f p1 = new Point3f(1.0f, 1.0f, 1.0f);

  private static final Point3f p2 = new Point3f(1.0f, -1.0f, 1.0f);

  private static final Point3f p3 = new Point3f(-1.0f, -1.0f, 1.0f);

  private static final Point3f p4 = new Point3f(-1.0f, 1.0f, 1.0f);

  private static final Point3f p5 = new Point3f(-1.0f, 1.0f, -1.0f);

  private static final Point3f p6 = new Point3f(-1.0f, -1.0f, -1.0f);

  private static final Point3f p7 = new Point3f(1.0f, -1.0f, -1.0f);

  private static final Point3f p8 = new Point3f(1.0f, 1.0f, -1.0f);

  // The 6 faces of the cube.
  private static final Point3f cubeFaces[] = { // external front face
  p5, p8, p7, p6,

  // external right face
      p8, p1, p2, p7,

      // external back face
      p1, p4, p3, p2,

      // external left face
      p4, p5, p6, p3,

      // external top face
      p8, p5, p4, p1,

      // external bottom face
      p2, p3, p6, p7 };

  // Coordinates in the texture space. Each cube's face has the
  // same texture coordinates.
  private TexCoord2f textCoord[] = { new TexCoord2f(1.0f, 1.0f),
      new TexCoord2f(0.0f, 1.0f), new TexCoord2f(0.0f, 0.0f),
      new TexCoord2f(1.0f, 0.0f) };
}

/**
 * This class is a switch behavior to control the rendering of the five
 * different earth's representations.
 */

class SwitchBehavior extends Behavior {
  // The Alpha class which gives the alpha values to command the Switch node.
  private Alpha switchAlpha;

  private float switchAlphaValue;

  // The class which contains the Switch node for the rendering of
  // the 5 different earth's representations.
  private SceneBuilder32 sceneBuilder32 = null;

  // The earth which will be rendered.
  private int thisEarth = 0;

  // Wakeup event after each frame.
  private WakeupOnElapsedFrames wakeUp = new WakeupOnElapsedFrames(0);

  /**
   * Constructor that allows to specify the reference of the SceneBuilder32's
   * instance.
   * 
   * @param sceneBuilder32 -
   *            the SceneBuilder32 instance
   */
  public SwitchBehavior(SceneBuilder32 sceneBuilder32) {
    super();

    // Create the alpha(t) function to automaticaly switch between the
    // five different earth's representations.
    switchAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE
        | Alpha.DECREASING_ENABLE, 0, 0, 10000, 0, 0, 10000, 0, 0);

    // Get the SceneBuilder32 reference
    this.sceneBuilder32 = sceneBuilder32;
  }

  /**
   * Override Behavior's initialize method to setup wakeup criteria.
   */
  public void initialize() {
    wakeupOn(wakeUp);
  }

  /**
   * Override Behavior's stimulus method to handle the event. This method is
   * called up when the define number of frames is draw.
   * 
   * @param criteria -
   *            the wake-up criteria
   */
  public void processStimulus(Enumeration criteria) {
    switchAlphaValue = switchAlpha.value();

    if (switchAlphaValue <= 0.15f)
      thisEarth = 0;
    else if (0.15f < switchAlphaValue && switchAlphaValue <= 0.4f)
      thisEarth = 1;
    else if (0.4f < switchAlphaValue && switchAlphaValue <= 0.6f)
      thisEarth = 2;
    else if (0.6f < switchAlphaValue && switchAlphaValue <= 0.8f)
      thisEarth = 3;
    else if (0.8f < switchAlphaValue)
      thisEarth = 4;

    sceneBuilder32.setNewEarth(thisEarth);

    // Set wakeup criteria for next time.
    wakeupOn(wakeUp);
  }
}

/**
 * This class creates a simple colored cube.
 */

class ColorCube extends Shape3D {
  private QuadArray cube;

  // The constant colors of each cube's face
  private static final Color3f red = new Color3f(1.0f, 0.0f, 0.0f);

  private static final Color3f green = new Color3f(0.0f, 1.0f, 0.0f);

  private static final Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);

  private static final Color3f yellow = new Color3f(1.0f, 1.0f, 0.0f);

  private static final Color3f magenta = new Color3f(1.0f, 0.0f, 1.0f);

  private static final Color3f cyan = new Color3f(0.0f, 1.0f, 1.0f);

  /**
   * Constructor that allows to specify the desired scale factor for the
   * colored cube.
   * 
   * @param type
   *            float s_XYZ - the scale factor to adjust the edges's length of
   *            the colored cube
   */
  public ColorCube(float scale_XYZ) { // 24
    cube = new QuadArray(cubeFaces.length, QuadArray.COORDINATES
        | QuadArray.COLOR_3);

    // Scaling of vertices
    for (int i = 0; i < cubeFaces.length; i++)
      cubeFaces[i].scale(scale_XYZ);

    cube.setCoordinates(0, cubeFaces);
    cube.setColors(0, colorsFaces);

    this.setGeometry(cube);
  }

  // The 8 vertices p1, ..., p8 of the cube.
  private static final Point3f p1 = new Point3f(1.0f, 1.0f, 1.0f);

  private static final Point3f p2 = new Point3f(-1.0f, 1.0f, 1.0f);

  private static final Point3f p3 = new Point3f(-1.0f, -1.0f, 1.0f);

  private static final Point3f p4 = new Point3f(1.0f, -1.0f, 1.0f);

  private static final Point3f p5 = new Point3f(1.0f, -1.0f, -1.0f);

  private static final Point3f p6 = new Point3f(1.0f, 1.0f, -1.0f);

  private static final Point3f p7 = new Point3f(-1.0f, 1.0f, -1.0f);

  private static final Point3f p8 = new Point3f(-1.0f, -1.0f, -1.0f);

  // The 6 faces of the cube.
  private static final Point3f cubeFaces[] = { // front face
  p1, p2, p3, p4,
  // right face
      p1, p4, p5, p6,
      // back face
      p8, p7, p6, p5,
      // left face
      p2, p7, p8, p3,
      // top face
      p1, p6, p7, p2,
      // bottom face
      p5, p4, p3, p8 };

  // The constant colors for the 6 faces.
  private static final Color3f[] colorsFaces = {// front face
  red, red, red, red,
  // back face
      green, green, green, green,
      // right face
      blue, blue, blue, blue,
      // left face
      yellow, yellow, yellow, yellow,
      // top face
      magenta, magenta, magenta, magenta,
      // bottom face
      cyan, cyan, cyan, cyan };
}

/**
 * This class is used to detach then add again the subgraph 32 from the scene
 * graph.
 */

/*
 * Note: It is not always necessary to use "detach" and "add" to add/remove a
 * subgraph from a scene graph. In many cases the using of the setEnable()
 * method, to turn a subgraph on and off, is adequate.
 */

class AddDetachEarthBehavior extends Behavior {
  // The classe which contains the addEarth method.
  private SceneBuilder3 sceneBuilder3;

  // The classe which contains the detachEarth method.
  private SceneBuilder32 sceneBuilder32;

  // To control the detach / add sequence.
  private boolean validation = false;

  // Wake up event when a key is pressed.
  private WakeupOnAWTEvent wakeUp = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);

  // The key event
  private KeyEvent keyEvent;

  /**
   * Constructor that allows to specify the references of the SceneBuilder3's
   * and SceneBuilder32's instances.
   * 
   * @param sceneBuilder3 -
   *            the SceneBuilder3 instance
   * @param sceneBuilder32 -
   *            the SceneBuilder32 instance
   */
  public AddDetachEarthBehavior(SceneBuilder3 sceneBuilder3,
      SceneBuilder32 sceneBuilder32) {
    super();

    // Get the SceneBuilder3's and SceneBuilder32's references
    this.sceneBuilder3 = sceneBuilder3;
    this.sceneBuilder32 = sceneBuilder32;
  }

  /**
   * Override Behavior's initialize method to setup wakeup criteria.
   */
  public void initialize() {
    wakeupOn(wakeUp);
  }

  /**
   * Override Behavior's stimulus method to handle the event. This method is
   * called when a key on the keyboard has been pressed and operates on the
   * specified transform group to move the camera.
   * 
   * @param Enumeration
   *            criteria - all pressed keys in a list. This will be passed by
   *            the system.
   */
  public void processStimulus(Enumeration criteria) {
    WakeupOnAWTEvent eventToWakeUp;
    AWTEvent[] events;

    if (criteria.hasMoreElements()) {
      // Decode the wakeup criteria
      eventToWakeUp = (WakeupOnAWTEvent) criteria.nextElement();
      events = eventToWakeUp.getAWTEvent();
      keyEvent = (KeyEvent) events[0];
      int keyCode = keyEvent.getKeyCode();

      // Perform our processing
      switch (keyCode) {
      case KeyEvent.VK_A:
        if (validation) {
          sceneBuilder3.addEarth();
          System.out.println("===>    Add Earth");
          validation = false;
        }
        break;

      case KeyEvent.VK_D:
        if (!validation) {
          sceneBuilder32.detachEarth();
          System.out.println("===>    Detach Earth");
          validation = true;
        }
        break;

      default:
      }
    }

    // Set wakeup criteria for next time.
    wakeupOn(wakeUp);
  }
}

/**
 * This class is a keyboard behavior to control the translation and the partly
 * rotation (turn left and turn right) of the camera.
 * 
 * After a translation or rotation performed by using this class, the
 * observation direction of the virtual camera will always stay parallel to the
 * coordinate system's (x-y)-plane of the parent node.
 * 
 * In the case of this Demo application, it will be the coordinate system
 * associated with the Locale node.
 */

class Camera_Transl_Turn extends Behavior {

  // The TransformGroup node to modify by the keyboard interaction.
  private TransformGroup target_trGr;

  // Wake up event when a key is pressed.
  private WakeupOnAWTEvent wakeUp = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);

  // The key event
  private KeyEvent keyEvent;

  // The angle to turn when a Direction Key and the Shift key are pressed.
  private float angle = (float) Math.PI / 36;

  // The step size to move when a Direction Key or the PageDown or
  // PageUp key is pressed.
  private float step = 1f;

  private Transform3D myKeyNavTransf3D = new Transform3D();

  private Vector3f translation = new Vector3f();

  private Vector3f dtrans = new Vector3f();

  private Vector3f dtrans0 = new Vector3f();

  private Transform3D trans_rot = new Transform3D();

  /**
   * Constructor that allows to specify the desired target transform group.
   * 
   * @param javax.media.j3d.TransformGroup
   *            target - the target transform group
   */
  public Camera_Transl_Turn(TransformGroup target) {
    target_trGr = target;
  }

  /**
   * Override Behavior's initialize method to setup wakeup criteria.
   */
  public void initialize() {
    wakeupOn(wakeUp);
  }

  /**
   * Override Behavior's stimulus method to handle the event. This method is
   * called when a key on the keyboard has been pressed and operates on the
   * specified transform group to move the camera.
   * 
   * @param Enumeration
   *            criteria - all pressed keys in a list. This will be passed by
   *            the system.
   */
  public void processStimulus(Enumeration criteria) {
    WakeupOnAWTEvent eventToWakeUp;
    AWTEvent[] events;

    if (criteria.hasMoreElements()) {
      // Decode the wakeup criteria
      eventToWakeUp = (WakeupOnAWTEvent) criteria.nextElement();
      events = eventToWakeUp.getAWTEvent();
      keyEvent = (KeyEvent) events[0];
      int keyCode = keyEvent.getKeyCode();

      // Perform our processing

      // Get the initial transformation from target and put it into
      // myKeyNavTransf3D
      target_trGr.getTransform(myKeyNavTransf3D);

      // Set the translational components of myKeyNavTransf3D in
      // translation
      myKeyNavTransf3D.get(translation);

      // Not any of the 8 motions (6 translations and 2 rotations)
      // don't act simultaneously.
      switch (keyCode) {
      case KeyEvent.VK_UP: // Up Arrow - to move forward
        trans_rot.set(new Vector3f(0.0f, 0.0f, -step));
        break;

      case KeyEvent.VK_DOWN: // Down Arrow - to move backwards
        trans_rot.set(new Vector3f(0.0f, 0.0f, step));
        break;

      case KeyEvent.VK_LEFT: // Left Arrow -to turn left or move left
        if (keyEvent.isShiftDown())
          trans_rot.set(new Vector3f(-step, 0.0f, 0.0f));
        else
          trans_rot.rotY(angle);
        break;

      case KeyEvent.VK_RIGHT: // Right Arrow - to turn right or move right
        if (keyEvent.isShiftDown())
          trans_rot.set(new Vector3f(step, 0.0f, 0.0f));
        else
          trans_rot.rotY(-angle);
        break;

      case KeyEvent.VK_PAGE_DOWN: // Page Down - to move down
        trans_rot.set(new Vector3f(0.0f, -step, 0.0f));
        break;

      case KeyEvent.VK_PAGE_UP: // Page Up - to move up
        trans_rot.set(new Vector3f(0.0f, step, 0.0f));
        break;

      default:
        trans_rot.set(new Vector3f(0.0f, 0.0f, 0.0f));
      }

      myKeyNavTransf3D.mul(trans_rot);

      // Return the final transformation myKeyNavTransf3D to target
      target_trGr.setTransform(myKeyNavTransf3D);
    }

    // Set wakeup criteria for next time.
    wakeupOn(wakeUp);
  }
}

/**
 * This class creates the Earth by using the Sphere class and a given texture
 * (Earth.jpg).
 */

class Earth {
  public Sphere earth;

  private String renderingType;

  private float scale_XYZ;

  private Color3f diffAmb, reflDiff, reflSpec, emittedLight;

  private float c; //  shininess;

  private Appearance appearance;

  private Material material;

  private ColoringAttributes coloringAttributes;

  private PolygonAttributes polygonAttributes;

  private NewTextureLoader newTextureLoader;

  private Texture texture;

  private TextureAttributes textAttr;

  /**
   * Constructor that allows to specify the desired rendering's mode and the
   * desired scale factor.
   * 
   * @param java.lang.String
   *            nom - the desired type of earth's rendering,
   * @param type
   *            float s_XYZ - the scale factor to adjust the earth's radius
   */
  public Earth(String name, float s_XYZ) {
    renderingType = name;
    scale_XYZ = s_XYZ;
  }

  /**
   * This methode serves to construct the earth.
   * 
   * @return com.sun.j3d.utils.geometry.Sphere earth - the constructed earth
   */
  public Sphere myEarth() {
    // Optical properties of the earth.

    // Ambient-diffuse-reflection coefficient
    diffAmb = new Color3f(1.0f, 1.0f, 1.0f);
    // Diffuse-reflection coefficient
    reflDiff = new Color3f(1.0f, 1.0f, 1.0f);
    // Specular-reflection coefficient (reflectance function)
    reflSpec = new Color3f(0.0f, 0.0f, 0.1f);
    // c = shininess: cos^c in the specular reflection
    c = 1;
    // Emitted light
    emittedLight = new Color3f(0.0f, 0.0f, 0.0f);

    appearance = new Appearance();

    // Create the material and set up the optical properties.
    material = new Material(diffAmb, emittedLight, reflDiff, reflSpec, c);
    appearance.setMaterial(material);

    // Set up the polygon's rendering-mode (with the polygonAttributes) and
    // the shading-mode (with the coloringAttributes).
    polygonAttributes = new PolygonAttributes();
    coloringAttributes = new ColoringAttributes();

    // Points
    if (renderingType.compareTo("points") == 0) {
      polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_POINT);
    }

    /* Lines*/
    else if (renderingType.compareTo("lines") == 0) {
      polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
    }

    /* Polygons */
    else if (renderingType.compareTo("polygons") == 0) {
      /* is the default value*/
      polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); 
      coloringAttributes.setShadeModel(ColoringAttributes.SHADE_FLAT);
    }

    /* Gouraud */
    else if (renderingType.compareTo("gouraud") == 0) {
      polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); /* is the default value*/
      coloringAttributes.setShadeModel(ColoringAttributes.SHADE_GOURAUD); /* is the default value*/
    }


    else if (renderingType.compareTo("texture") == 0) {
      polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); /* is the default value*/
      coloringAttributes.setShadeModel(ColoringAttributes.SHADE_GOURAUD); /* is the default value*/

      /* Loading of the texture*/
      newTextureLoader = new NewTextureLoader("Images/Earth.jpg");
      newTextureLoader.setImageObserver(newTextureLoader
          .getImageObserver());
      texture = newTextureLoader.getTexture();

      appearance.setTexture(texture);

      /* Application mode of the texture */
      textAttr = new TextureAttributes();
      textAttr.setTextureMode(TextureAttributes.REPLACE); /* there still are:
       BLEND, COMBINE,
       DECAL, and MODULATE*/
      appearance.setTextureAttributes(textAttr);
    }

    appearance.setPolygonAttributes(polygonAttributes);
    appearance.setColoringAttributes(coloringAttributes);

    /* Construction of the earth with all its features.*/
        earth = new Sphere(scale_XYZ, Sphere.GENERATE_NORMALS
        | Sphere.GENERATE_TEXTURE_COORDS, 10, appearance);
    return earth;
  }
}

/**
 * This class creates a tetrahedron with a given texture (Claude.jpg).
 */

class Tetrahedron extends Shape3D {
  private float scale_XYZ;

  private Point3f vertices[];

  private int lengthVertices = 4, lengthTetraFaceIndices = 12; // 4 faces x 3
                                 // vertices

  private int tetraFaceIndices[], textCoordIndices[];

  private GeometryInfo tetra_GeometryInfo;

  private NormalGenerator normalGenerator;

  private Stripifier stripifier;

  private GeometryArray tetra_GeometryArray;

  private TexCoord2f textCoord2f[]; // for triangles

  private boolean crAngle;

  private Appearance appearance;

  private Color3f diffAmb, reflDiff, reflSpec, emittedLight;

  private Material material;

  private TransparencyAttributes trAttr;

  private NewTextureLoader newTextureLoader;

  private Texture texture;

  private TextureAttributes textAttr;

  /**
   * Constructor that allows to specify the desired scale factor.
   * 
   * @param type
   *            float s_XYZ - the scale factor to adjust the edges's length of
   *            the tetrahedron
   */
  public Tetrahedron(float s_XYZ) {
    scale_XYZ = s_XYZ;
  }

  /**
   * Construction of the desired tetrahedron.
   * 
   * @return javax.media.j3d.Shape3D myTetrahedron - the constructed
   *         tetrahedron
   */
  public Shape3D myTetrahedron() {

    ////////////////////// Geometric part ///////////////////////////

    // The 4 vertices p0, p1, p2 and p3 of the tetrahedron.
    vertices = new Point3f[lengthVertices]; // 4
    vertices[0] = new Point3f(0.0f, 0.0f, 0.0f);
    vertices[1] = new Point3f(1.0f, 0.0f, 0.0f);
    vertices[2] = new Point3f(0.0f, 1.0f, 0.0f);
    vertices[3] = new Point3f(0.0f, 0.0f, 1.0f);

    // Scaling of vertices
    for (int i = 0; i < lengthVertices; i++)
      // lengthVertices = 4
      vertices[i].scale(scale_XYZ);

    // Set the face's indices for the tetrahedron (referenced to the array
    // of vertices
    // by setCoordinates(vertices) and
    // setCoordinateIndices(tetraFaceIndices)).
    tetraFaceIndices = new int[lengthTetraFaceIndices]; // 12
    // From the camera in the view coordinate system
    // bottom
    tetraFaceIndices[0] = 0;
    tetraFaceIndices[1] = 1;
    tetraFaceIndices[2] = 3;
    // back-left face
    tetraFaceIndices[3] = 0;
    tetraFaceIndices[4] = 3;
    tetraFaceIndices[5] = 2;
    // back face
    tetraFaceIndices[6] = 0;
    tetraFaceIndices[7] = 2;
    tetraFaceIndices[8] = 1;
    // front face
    tetraFaceIndices[9] = 1;
    tetraFaceIndices[10] = 2;
    tetraFaceIndices[11] = 3;

    // Create the GeometryInfo instance and set the vertices
    tetra_GeometryInfo = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
    tetra_GeometryInfo.setCoordinates(vertices);
    tetra_GeometryInfo.setCoordinateIndices(tetraFaceIndices);

    //      triangulator = new Triangulator(); // only for polygons:
    // POLYGON_ARRAY
    //      triangulator.triangulate(tetra_GeometryInfo); // and with: int
    // stripCounts[]
    //           gi.setStripCounts(...)
    //           int contourCounts[]

    // Set the parameters (1 texture with dimension 2) for the texture's
    // coordinates
    tetra_GeometryInfo.setTextureCoordinateParams(1, 2);

    //    case #1: each face of the tetrahedron has the same texture portion.

    // The coordinates of the 3 points in the 2D texture space.
    textCoord2f = new TexCoord2f[3];
    textCoord2f[0] = new TexCoord2f(0.0f, 0.2f);
    textCoord2f[1] = new TexCoord2f(0.5f, 1.0f);
    textCoord2f[2] = new TexCoord2f(1.0f, 0.5f);

    // Set the texture coordinate's indices (referenced to the array of 2D
    // points
    // in the texture space by setTextureCoordinates(0, textCoord2f) and
    // setTextureCoordinateIndices(0, textCoordIndices)).
    textCoordIndices = new int[lengthTetraFaceIndices]; // 12

    // From the camera in the view coordinate system (inverse of
    // tetraFaceIndices !!!)
    // front face
    textCoordIndices[0] = 0;
    textCoordIndices[1] = 1;
    textCoordIndices[2] = 2;
    // back face
    textCoordIndices[3] = 0;
    textCoordIndices[4] = 1;
    textCoordIndices[5] = 2;
    // back-left face
    textCoordIndices[6] = 2;
    textCoordIndices[7] = 0;
    textCoordIndices[8] = 1;
    // bottom
    textCoordIndices[9] = 0;
    textCoordIndices[10] = 1;
    textCoordIndices[11] = 2;

    /*
     * // case #2: each face of the tetrahedron has a different part of the
     * texture.
     *  // The coordinates of the 4 points in the 2D texture space.
     * textCoord2f = new TexCoord2f[4]; textCoord2f[0] = new
     * TexCoord2f(0.0f, 0.5f); textCoord2f[1] = new TexCoord2f(1.0f, 0.5f);
     * textCoord2f[2] = new TexCoord2f(0.6f, 0.7f); textCoord2f[3] = new
     * TexCoord2f(0.6f, 0.3f);
     * 
     *  // Set the texture coordinate's indices (referenced to the array of
     * 2D points // in the texture space by setTextureCoordinates(0,
     * textCoord2f) and // setTextureCoordinateIndices(0,
     * textCoordIndices)). textCoordIndices = new
     * int[lengthTetraFaceIndices]; // 12
     *  // From the camera in the view coordinate system (inverse of
     * tetraFaceIndices !!!) // front face textCoordIndices[0] = 3;
     * textCoordIndices[1] = 2; textCoordIndices[2] = 0; // back face
     * textCoordIndices[3] = 1; textCoordIndices[4] = 2; textCoordIndices[5] =
     * 3; // back-left face textCoordIndices[6] = 1; textCoordIndices[7] =
     * 0; textCoordIndices[8] = 2; // bottom textCoordIndices[9] = 1;
     * textCoordIndices[10]= 3; textCoordIndices[11]= 0;
     */
    // just one set
    tetra_GeometryInfo.setTextureCoordinates(0, textCoord2f);
    // just one set
    tetra_GeometryInfo.setTextureCoordinateIndices(0, textCoordIndices);

    normalGenerator = new NormalGenerator();
    normalGenerator.generateNormals(tetra_GeometryInfo);

    if (crAngle)
      normalGenerator.setCreaseAngle(0.0f); // with 0 radian ===> creased

    stripifier = new Stripifier();
    stripifier.stripify(tetra_GeometryInfo);

    tetra_GeometryArray = tetra_GeometryInfo.getGeometryArray();

    // The geonometry is passed to the instance this of the tetrahedron.
    this.setGeometry(tetra_GeometryArray);

    ////////////////////// Appearance part ///////////////////////////

    appearance = new Appearance();

    // Optical properties of the tetrahedron.

    // Ambient-diffuse-reflection coefficient
    diffAmb = new Color3f(1.0f, 0.5f, 1.0f);
    // Diffuse-reflection coefficient
    reflDiff = new Color3f(1.0f, 0.5f, 1.0f);
    // Specular-reflection coefficient (reflectance function)
    reflSpec = new Color3f(1.0f, 0.5f, 1.0f);
    // c = shininess: cos^c in the specular reflection
    float c = 15;
    // Emitted light
    emittedLight = new Color3f(0.0f, 0.0f, 0.0f);

    material = new Material(diffAmb, emittedLight, reflDiff, reflSpec, c);
    appearance.setMaterial(material);

    // This instance acts only on the tetrahedron and not on its texture.
    trAttr = new TransparencyAttributes(TransparencyAttributes.NICEST, 0.0f);
    // 0.0 = fully opaque
    // 1.0 = fully transparent
    appearance.setTransparencyAttributes(trAttr);

    // Loading the texture
    newTextureLoader = new NewTextureLoader("Images/Claude.jpg");
    newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());

    texture = newTextureLoader.getTexture();

    appearance.setTexture(texture);

    // Application mode of the texture
    textAttr = new TextureAttributes();
    textAttr.setTextureMode(TextureAttributes.MODULATE); // there still are:
    // BLEND, COMBINE,
    // DECAL, and REPLACE
    appearance.setTextureAttributes(textAttr);

    // The appearance is passed to the instance this of the tetrahedron.
    this.setAppearance(appearance);

    return this;
  }
}

/**
 * This class creates a right-handed 3D coordinate system.
 */

class CoordSyst extends Shape3D {
  private float rX, gX, bX, rY, gY, bY, rZ, gZ, bZ, scale_XYZ;

  private LineArray axes;

  private float scaledExtremites[];

  /**
   * Constructor that allows to specify the desired initial colors and the
   * length of the axes.
   * 
   * @param type
   *            float rougeX, vertX, bleuX, rougeY, vertY, bleuY, rougeZ,
   *            vertZ, bleuZ - the colors of the axes
   * @param type
   *            float s_XYZ - the scale factor to adjust the axes's length
   */
  public CoordSyst(float rougeX, float vertX, float bleuX, float rougeY,
      float vertY, float bleuY, float rougeZ, float vertZ, float bleuZ,
      float s_XYZ) {
    rX = rougeX;
    rY = rougeY;
    rZ = rougeZ;
    gX = vertX;
    gY = vertY;
    gZ = vertZ;
    bX = bleuX;
    bY = bleuY;
    bZ = bleuZ;
    scale_XYZ = s_XYZ;

    // Colors of the three axes.
    float color[] = { rX, gX, bX, rX, gX, bX, // the x axis
        rY, gY, bY, rY, gY, bY, // the y axis
        rZ, gZ, bZ, rZ, gZ, bZ }; // the z axis

    // Construction of the axes (LineArray).
    axes = new LineArray(6, LineArray.COORDINATES | LineArray.COLOR_3);

    // Scalling of the vertices of the 3 axes using scale_XYZ.
    scaledExtremites = new float[extremites.length];
    for (int i = 0; i < extremites.length; i++)
      scaledExtremites[i] = extremites[i] * scale_XYZ;

    axes.setCoordinates(0, scaledExtremites);
    axes.setColors(0, color);

    this.setGeometry(axes);
  }

  // Definition of the geometry of the three axes.
  private static final float extremites[] = {
  // x-axis
      0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

      // y-axis
      0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,

      // z-axis
      0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
}


           
       








Related examples in the same category

1.Hello Universe 1Hello Universe 1
2.Simple UniverseSimple Universe
3.Creates a scene with a different scaleCreates a scene with a different scale
4.Scenegraph that illustrates many of the Java 3D scenegraph NodesScenegraph that illustrates many of the Java 3D scenegraph Nodes
5.Illustrate some of the features of the SimpleUniverse class
6.Demonstrate the use of the Universe builder forDemonstrate the use of the Universe builder for
7.MainFrame and SimpleUniverseMainFrame and SimpleUniverse
8.A Switch Node and conditionally displays some of the child NodesA Switch Node and conditionally displays some of the child Nodes
9.Example AppearanceExample Appearance