Mega Code Archive

 
Categories / Java / 3D Graphics
 

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 }; }