Java/3D/Universe Node

Материал из Java эксперт
Перейти к: навигация, поиск

A Switch Node and conditionally displays some of the child Nodes

   <source lang="java">

/**********************************************************

Copyright (C) 2001   Daniel Selman
First distributed with the book "Java 3D Programming"
by Daniel Selman and published by Manning Publications.
http://manning.ru/selman
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
The license can be found on the WWW at:
http://www.fsf.org/copyleft/gpl.html
Or by writing to:
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
Authors can be contacted at:
Daniel Selman: daniel@selman.org
If you make changes you think others would like, please 
contact one of the authors or someone at the 
www.j3d.org web site.
**************************************************************/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Font; import java.awt.GraphicsConfigTemplate; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.io.File; import java.net.URL; import javax.media.j3d.AudioDevice; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.Bounds; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.media.j3d.Group; import javax.media.j3d.Locale; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.Switch; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.View; import javax.media.j3d.ViewPlatform; import javax.media.j3d.VirtualUniverse; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Text2D; /**

* This example creates a Switch Node and conditionally displays some of the
* child Nodes using a logical mask, defined using a BitSet object.
*/

public class SwitchTest extends Java3dApplet {

 private static final int m_kWidth = 400;
 private static final int m_kHeight = 400;
 static int m_nLabelNumber = 0;
 public SwitchTest() {
   initJava3d();
 }
 protected BranchGroup createSceneBranchGroup() {
   BranchGroup objRoot = super.createSceneBranchGroup();
   double labelScale = 20;
   // flip this boolean to either display all
   // the child nodes or to just display the 3, 6 and 7th.
   final boolean bDisplayAll = false;
   // create the Switch Node
   int nMode = Switch.CHILD_ALL;
   if (bDisplayAll == false)
     nMode = Switch.CHILD_MASK;
   Switch switchGroup = new Switch(nMode);
   switchGroup.setCapability(Switch.ALLOW_SWITCH_WRITE);
   switchGroup.addChild(createLabel("Child Node 1", labelScale));
   switchGroup.addChild(createLabel("Child Node 2", labelScale));
   switchGroup.addChild(createLabel("Child Node 3", labelScale));
   switchGroup.addChild(createLabel("Child Node 4", labelScale));
   switchGroup.addChild(createLabel("Child Node 5", labelScale));
   switchGroup.addChild(createLabel("Child Node 6", labelScale));
   switchGroup.addChild(createLabel("Child Node 7", labelScale));
   if (bDisplayAll == false) {
     java.util.BitSet visibleNodes = new java.util.BitSet(switchGroup
         .numChildren());
     // make the third, sixth and seventh nodes visible
     visibleNodes.set(2);
     visibleNodes.set(5);
     visibleNodes.set(6);
     switchGroup.setChildMask(visibleNodes);
   }
   // finally add the Switch Node
   objRoot.addChild(switchGroup);
   return objRoot;
 }
 // creates a Text2D label and scales it
 // the method shifts each label created downwards.
 // Note that the labels on adjacent lines will overlap
 // so we can illustrate the function of the OrderedGroup
 TransformGroup createLabel(String szText, double scale) {
   Color3f colorText = new Color3f();
   int nFontSizeText = 10;
   Text2D label3D = new Text2D(szText, colorText, "SansSerif",
       nFontSizeText, Font.PLAIN);
   TransformGroup tg = new TransformGroup();
   Transform3D t3d = new Transform3D();
   t3d.setTranslation(new Vector3d(-8, 1.5 * (3 - m_nLabelNumber), 0));
   t3d.setScale(scale);
   tg.setTransform(t3d);
   tg.addChild(label3D);
   m_nLabelNumber++;
   return tg;
 }
 public static void main(String[] args) {
   SwitchTest SwitchTest = new SwitchTest();
   SwitchTest.saveCommandLineArguments(args);
   new MainFrame(SwitchTest, m_kWidth, m_kHeight);
 }

} /*******************************************************************************

* Copyright (C) 2001 Daniel Selman
* 
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.ru/selman
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
* 
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
* 
* Authors can be contacted at: Daniel Selman: daniel@selman.org
* 
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/

//***************************************************************************** /**

* Java3dApplet
* 
* Base class for defining a Java 3D applet. Contains some useful methods for
* defining views and scenegraphs etc.
* 
* @author Daniel Selman
* @version 1.0
*/

//***************************************************************************** abstract class Java3dApplet extends Applet {

 public static int m_kWidth = 300;
 public static int m_kHeight = 300;
 protected String[] m_szCommandLineArray = null;
 protected VirtualUniverse m_Universe = null;
 protected BranchGroup m_SceneBranchGroup = null;
 protected Bounds m_ApplicationBounds = null;
 //  protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;
 public Java3dApplet() {
 }
 public boolean isApplet() {
   try {
     System.getProperty("user.dir");
     System.out.println("Running as Application.");
     return false;
   } catch (Exception e) {
   }
   System.out.println("Running as Applet.");
   return true;
 }
 public URL getWorkingDirectory() throws java.net.MalformedURLException {
   URL url = null;
   try {
     File file = new File(System.getProperty("user.dir"));
     System.out.println("Running as Application:");
     System.out.println("   " + file.toURL());
     return file.toURL();
   } catch (Exception e) {
   }
   System.out.println("Running as Applet:");
   System.out.println("   " + getCodeBase());
   return getCodeBase();
 }
 public VirtualUniverse getVirtualUniverse() {
   return m_Universe;
 }
 //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
 //return m_Java3dTree;
 //  }
 public Locale getFirstLocale() {
   java.util.Enumeration e = m_Universe.getAllLocales();
   if (e.hasMoreElements() != false)
     return (Locale) e.nextElement();
   return null;
 }
 protected Bounds getApplicationBounds() {
   if (m_ApplicationBounds == null)
     m_ApplicationBounds = createApplicationBounds();
   return m_ApplicationBounds;
 }
 protected Bounds createApplicationBounds() {
   m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   return m_ApplicationBounds;
 }
 protected Background createBackground() {
   Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
   back.setApplicationBounds(createApplicationBounds());
   return back;
 }
 public void initJava3d() {
   //  m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
   m_Universe = createVirtualUniverse();
   Locale locale = createLocale(m_Universe);
   BranchGroup sceneBranchGroup = createSceneBranchGroup();
   ViewPlatform vp = createViewPlatform();
   BranchGroup viewBranchGroup = createViewBranchGroup(
       getViewTransformGroupArray(), vp);
   createView(vp);
   Background background = createBackground();
   if (background != null)
     sceneBranchGroup.addChild(background);
   //    m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
   //  m_Java3dTree.recursiveApplyCapability(viewBranchGroup);
   locale.addBranchGraph(sceneBranchGroup);
   addViewBranchGroup(locale, viewBranchGroup);
   onDoneInit();
 }
 protected void onDoneInit() {
   //  m_Java3dTree.updateNodes(m_Universe);
 }
 protected double getScale() {
   return 1.0;
 }
 public TransformGroup[] getViewTransformGroupArray() {
   TransformGroup[] tgArray = new TransformGroup[1];
   tgArray[0] = new TransformGroup();
   // move the camera BACK a little...
   // note that we have to invert the matrix as
   // we are moving the viewer
   Transform3D t3d = new Transform3D();
   t3d.setScale(getScale());
   t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
   t3d.invert();
   tgArray[0].setTransform(t3d);
   return tgArray;
 }
 protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
   locale.addBranchGraph(bg);
 }
 protected Locale createLocale(VirtualUniverse u) {
   return new Locale(u);
 }
 protected BranchGroup createSceneBranchGroup() {
   m_SceneBranchGroup = new BranchGroup();
   return m_SceneBranchGroup;
 }
 protected View createView(ViewPlatform vp) {
   View view = new View();
   PhysicalBody pb = createPhysicalBody();
   PhysicalEnvironment pe = createPhysicalEnvironment();
   AudioDevice audioDevice = createAudioDevice(pe);
   if (audioDevice != null) {
     pe.setAudioDevice(audioDevice);
     audioDevice.initialize();
   }
   view.setPhysicalEnvironment(pe);
   view.setPhysicalBody(pb);
   if (vp != null)
     view.attachViewPlatform(vp);
   view.setBackClipDistance(getBackClipDistance());
   view.setFrontClipDistance(getFrontClipDistance());
   Canvas3D c3d = createCanvas3D();
   view.addCanvas3D(c3d);
   addCanvas3D(c3d);
   return view;
 }
 protected PhysicalBody createPhysicalBody() {
   return new PhysicalBody();
 }
 protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
   JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);
   if (javaSoundMixer == null)
     System.out.println("create of audiodevice failed");
   return javaSoundMixer;
 }
 protected PhysicalEnvironment createPhysicalEnvironment() {
   return new PhysicalEnvironment();
 }
 protected float getViewPlatformActivationRadius() {
   return 100;
 }
 protected ViewPlatform createViewPlatform() {
   ViewPlatform vp = new ViewPlatform();
   vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
   vp.setActivationRadius(getViewPlatformActivationRadius());
   return vp;
 }
 protected Canvas3D createCanvas3D() {
   GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
   gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
   GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
       .getScreenDevices();
   Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
   c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
   return c3d;
 }
 protected int getCanvas3dWidth(Canvas3D c3d) {
   return m_kWidth;
 }
 protected int getCanvas3dHeight(Canvas3D c3d) {
   return m_kHeight;
 }
 protected double getBackClipDistance() {
   return 100.0;
 }
 protected double getFrontClipDistance() {
   return 1.0;
 }
 protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray,
     ViewPlatform vp) {
   BranchGroup vpBranchGroup = new BranchGroup();
   if (tgArray != null && tgArray.length > 0) {
     Group parentGroup = vpBranchGroup;
     TransformGroup curTg = null;
     for (int n = 0; n < tgArray.length; n++) {
       curTg = tgArray[n];
       parentGroup.addChild(curTg);
       parentGroup = curTg;
     }
     tgArray[tgArray.length - 1].addChild(vp);
   } else
     vpBranchGroup.addChild(vp);
   return vpBranchGroup;
 }
 protected void addCanvas3D(Canvas3D c3d) {
   setLayout(new BorderLayout());
   add(c3d, BorderLayout.CENTER);
   doLayout();
 }
 protected VirtualUniverse createVirtualUniverse() {
   return new VirtualUniverse();
 }
 protected void saveCommandLineArguments(String[] szArgs) {
   m_szCommandLineArray = szArgs;
 }
 protected String[] getCommandLineArguments() {
   return m_szCommandLineArray;
 }

}


      </source>
   
  
 
  



Creates a scene with a different scale

   <source lang="java">

/**********************************************************

Copyright (C) 2001   Daniel Selman
First distributed with the book "Java 3D Programming"
by Daniel Selman and published by Manning Publications.
http://manning.ru/selman
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
The license can be found on the WWW at:
http://www.fsf.org/copyleft/gpl.html
Or by writing to:
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
Authors can be contacted at:
Daniel Selman: daniel@selman.org
If you make changes you think others would like, please 
contact one of the authors or someone at the 
www.j3d.org web site.
**************************************************************/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Button; import java.awt.GraphicsConfigTemplate; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.net.URL; import javax.media.j3d.Alpha; import javax.media.j3d.Appearance; import javax.media.j3d.AudioDevice; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.Bounds; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.media.j3d.Group; import javax.media.j3d.Locale; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Texture; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.View; import javax.media.j3d.ViewPlatform; import javax.media.j3d.VirtualUniverse; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.image.TextureLoader; /**

* Creates a new into a Java 3D scene each time the "Add View" button is
* pressed. Each view has a different scale set so you can tell them apart.
*/

public class MultiView extends Java3dApplet implements ActionListener {

 private static final int m_kWidth = 400;
 private static final int m_kHeight = 400;
 private static final int m_kCanvasSize = 100;
 private int m_nNumViews;
 public MultiView() {
   m_nNumViews = 0;
   initJava3d();
 }
 protected void addCanvas3D(Canvas3D c3d) {
   add(c3d);
   // IFF we have created the first view
   // also add a button to allow more views
   // to be created
   if (m_nNumViews == 1) {
     Button button = new Button("Add View");
     button.addActionListener(this);
     add(button);
   }
   doLayout();
 }
 protected int getCanvas3dWidth(Canvas3D c3d) {
   return m_kCanvasSize;
 }
 protected int getCanvas3dHeight(Canvas3D c3d) {
   return m_kCanvasSize;
 }
 public BranchGroup createSceneBranchGroup() {
   // Create the root of the branch graph
   BranchGroup objRoot = new BranchGroup();
   //Make the scene graph
   try {
     TransformGroup objTrans = new TransformGroup();
     objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
     objRoot.addChild(objTrans);
     // Create appearance object for textured cube
     Appearance app = new Appearance();
     Texture tex = new TextureLoader("Dog.jpg", this).getTexture();
     app.setTexture(tex);
     // Create a simple shape leaf node, add it to the scene graph.
     Box textureCube = new Box(2, 3, 4, Box.GENERATE_TEXTURE_COORDS, app);
     objTrans.addChild(textureCube);
     // Create a new Behavior object that will perform the desired
     // operation on the specified transform object and add it into
     // the scene graph.
     Transform3D yAxis = new Transform3D();
     Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
         4000, 0, 0, 0, 0, 0);
     RotationInterpolator rotator = new RotationInterpolator(
         rotationAlpha, objTrans, yAxis, 0.0f,
         (float) Math.PI * 2.0f);
     BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0,
         0.0), 100.0);
     rotator.setSchedulingBounds(bounds);
     objTrans.addChild(rotator);
   } catch (RuntimeException e) {
     System.out.println("MultiView.createSceneBranchGroup:"
         + e.getMessage());
     System.exit(-1);
   }
   return objRoot;
 }
 public TransformGroup[] getViewTransformGroupArray() {
   // increment the view count
   m_nNumViews++;
   TransformGroup[] tgArray = new TransformGroup[1];
   tgArray[0] = new TransformGroup();
   Vector3d vTrans = new Vector3d(0.0, 0.0, -20);
   // move the camera BACK so we can view the scene
   // also set the scale so that the more views we have
   // the smaller the scene will be scaled
   Transform3D t3d = new Transform3D();
   t3d.setTranslation(vTrans);
   t3d.setScale(1.0 / m_nNumViews);
   t3d.invert();
   tgArray[0].setTransform(t3d);
   return tgArray;
 }
 public void actionPerformed(ActionEvent event) {
   if (event.getActionCommand().equals("Add View") != false) {
     // create a new ViewPlatform
     ViewPlatform vp = createViewPlatform();
     // create the BranchGroup for the ViewPlatform
     BranchGroup viewBranchGroup = createViewBranchGroup(
         getViewTransformGroupArray(), vp);
     // add the ViewPlatform BranchGroup to the default Locale
     addViewBranchGroup(getFirstLocale(), viewBranchGroup);
     // create the View (including Canvas3D) and attach to the
     // ViewPlatform
     createView(vp);
   }
 }
 public static void main(String args[]) {
   MultiView multiView = new MultiView();
   multiView.saveCommandLineArguments(args);
   new MainFrame(multiView, m_kWidth, m_kHeight);
 }

} /*******************************************************************************

* Copyright (C) 2001 Daniel Selman
* 
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.ru/selman
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
* 
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
* 
* Authors can be contacted at: Daniel Selman: daniel@selman.org
* 
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/

//***************************************************************************** /**

* Java3dApplet
* 
* Base class for defining a Java 3D applet. Contains some useful methods for
* defining views and scenegraphs etc.
* 
* @author Daniel Selman
* @version 1.0
*/

//***************************************************************************** abstract class Java3dApplet extends Applet {

 public static int m_kWidth = 300;
 public static int m_kHeight = 300;
 protected String[] m_szCommandLineArray = null;
 protected VirtualUniverse m_Universe = null;
 protected BranchGroup m_SceneBranchGroup = null;
 protected Bounds m_ApplicationBounds = null;
 //  protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;
 public Java3dApplet() {
 }
 public boolean isApplet() {
   try {
     System.getProperty("user.dir");
     System.out.println("Running as Application.");
     return false;
   } catch (Exception e) {
   }
   System.out.println("Running as Applet.");
   return true;
 }
 public URL getWorkingDirectory() throws java.net.MalformedURLException {
   URL url = null;
   try {
     File file = new File(System.getProperty("user.dir"));
     System.out.println("Running as Application:");
     System.out.println("   " + file.toURL());
     return file.toURL();
   } catch (Exception e) {
   }
   System.out.println("Running as Applet:");
   System.out.println("   " + getCodeBase());
   return getCodeBase();
 }
 public VirtualUniverse getVirtualUniverse() {
   return m_Universe;
 }
 //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
 //return m_Java3dTree;
 //  }
 public Locale getFirstLocale() {
   java.util.Enumeration e = m_Universe.getAllLocales();
   if (e.hasMoreElements() != false)
     return (Locale) e.nextElement();
   return null;
 }
 protected Bounds getApplicationBounds() {
   if (m_ApplicationBounds == null)
     m_ApplicationBounds = createApplicationBounds();
   return m_ApplicationBounds;
 }
 protected Bounds createApplicationBounds() {
   m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   return m_ApplicationBounds;
 }
 protected Background createBackground() {
   Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
   back.setApplicationBounds(createApplicationBounds());
   return back;
 }
 public void initJava3d() {
   //  m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
   m_Universe = createVirtualUniverse();
   Locale locale = createLocale(m_Universe);
   BranchGroup sceneBranchGroup = createSceneBranchGroup();
   ViewPlatform vp = createViewPlatform();
   BranchGroup viewBranchGroup = createViewBranchGroup(
       getViewTransformGroupArray(), vp);
   createView(vp);
   Background background = createBackground();
   if (background != null)
     sceneBranchGroup.addChild(background);
   //    m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
   //  m_Java3dTree.recursiveApplyCapability(viewBranchGroup);
   locale.addBranchGraph(sceneBranchGroup);
   addViewBranchGroup(locale, viewBranchGroup);
   onDoneInit();
 }
 protected void onDoneInit() {
   //  m_Java3dTree.updateNodes(m_Universe);
 }
 protected double getScale() {
   return 1.0;
 }
 public TransformGroup[] getViewTransformGroupArray() {
   TransformGroup[] tgArray = new TransformGroup[1];
   tgArray[0] = new TransformGroup();
   // move the camera BACK a little...
   // note that we have to invert the matrix as
   // we are moving the viewer
   Transform3D t3d = new Transform3D();
   t3d.setScale(getScale());
   t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
   t3d.invert();
   tgArray[0].setTransform(t3d);
   return tgArray;
 }
 protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
   locale.addBranchGraph(bg);
 }
 protected Locale createLocale(VirtualUniverse u) {
   return new Locale(u);
 }
 protected BranchGroup createSceneBranchGroup() {
   m_SceneBranchGroup = new BranchGroup();
   return m_SceneBranchGroup;
 }
 protected View createView(ViewPlatform vp) {
   View view = new View();
   PhysicalBody pb = createPhysicalBody();
   PhysicalEnvironment pe = createPhysicalEnvironment();
   AudioDevice audioDevice = createAudioDevice(pe);
   if (audioDevice != null) {
     pe.setAudioDevice(audioDevice);
     audioDevice.initialize();
   }
   view.setPhysicalEnvironment(pe);
   view.setPhysicalBody(pb);
   if (vp != null)
     view.attachViewPlatform(vp);
   view.setBackClipDistance(getBackClipDistance());
   view.setFrontClipDistance(getFrontClipDistance());
   Canvas3D c3d = createCanvas3D();
   view.addCanvas3D(c3d);
   addCanvas3D(c3d);
   return view;
 }
 protected PhysicalBody createPhysicalBody() {
   return new PhysicalBody();
 }
 protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
   JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);
   if (javaSoundMixer == null)
     System.out.println("create of audiodevice failed");
   return javaSoundMixer;
 }
 protected PhysicalEnvironment createPhysicalEnvironment() {
   return new PhysicalEnvironment();
 }
 protected float getViewPlatformActivationRadius() {
   return 100;
 }
 protected ViewPlatform createViewPlatform() {
   ViewPlatform vp = new ViewPlatform();
   vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
   vp.setActivationRadius(getViewPlatformActivationRadius());
   return vp;
 }
 protected Canvas3D createCanvas3D() {
   GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
   gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
   GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
       .getScreenDevices();
   Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
   c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
   return c3d;
 }
 protected int getCanvas3dWidth(Canvas3D c3d) {
   return m_kWidth;
 }
 protected int getCanvas3dHeight(Canvas3D c3d) {
   return m_kHeight;
 }
 protected double getBackClipDistance() {
   return 100.0;
 }
 protected double getFrontClipDistance() {
   return 1.0;
 }
 protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray,
     ViewPlatform vp) {
   BranchGroup vpBranchGroup = new BranchGroup();
   if (tgArray != null && tgArray.length > 0) {
     Group parentGroup = vpBranchGroup;
     TransformGroup curTg = null;
     for (int n = 0; n < tgArray.length; n++) {
       curTg = tgArray[n];
       parentGroup.addChild(curTg);
       parentGroup = curTg;
     }
     tgArray[tgArray.length - 1].addChild(vp);
   } else
     vpBranchGroup.addChild(vp);
   return vpBranchGroup;
 }
 protected void addCanvas3D(Canvas3D c3d) {
   setLayout(new BorderLayout());
   add(c3d, BorderLayout.CENTER);
   doLayout();
 }
 protected VirtualUniverse createVirtualUniverse() {
   return new VirtualUniverse();
 }
 protected void saveCommandLineArguments(String[] szArgs) {
   m_szCommandLineArray = szArgs;
 }
 protected String[] getCommandLineArguments() {
   return m_szCommandLineArray;
 }

}


      </source>
   
  
 
  



Demonstrate the use of the Universe builder for

   <source lang="java">

/*

*  @(#)SimpleGeometry.java 1.16 02/10/21 13:50:17
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
*   notice, this list of conditions and the following disclaimer in
*   the documentation and/or other materials provided with the
*   distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 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.
*
* You acknowledge that Software is not designed,licensed or intended
* for use in the design, construction, operation or maintenance of
* any nuclear facility.
*/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.GraphicsConfiguration; import javax.media.j3d.Alpha; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TransparencyAttributes; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.behaviors.mouse.MouseTranslate; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.geometry.Cylinder; import com.sun.j3d.utils.universe.PlatformGeometry; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewingPlatform; /**

* This class demonstrates the use of the Universe builder for stand-alone
* applications along with the use of the PlatformGeometry node that is present
* in the Java 3D Universe Builder utility. The standard HelloWorld application
* is brought up. A transparent cylinder has been added to the PlatfromGeometry
* node of the ViewingPlatform and the MouseTranslate utility has been used to
* allow this sphere to be dragged around the canvas.
*/

public class SimpleGeometry extends Applet {

 SimpleUniverse u = null;
 public BranchGroup createSceneGraph() {
   // Create the root of the branch graph
   BranchGroup objRoot = new BranchGroup();
   // Create a Transformgroup to scale all objects so they
   // appear in the scene.
   TransformGroup objScale = new TransformGroup();
   Transform3D t3d = new Transform3D();
   t3d.setScale(0.4);
   objScale.setTransform(t3d);
   objRoot.addChild(objScale);
   // Create the transform group node and initialize it to the
   // identity. Enable the TRANSFORM_WRITE capability so that
   // our behavior code can modify it at runtime. Add it to the
   // root of the subgraph.
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objScale.addChild(objTrans);
   // Create a simple shape leaf node, add it to the scene graph.
   objTrans.addChild(new ColorCube());
   // Create a new Behavior object that will perform the desired
   // operation on the specified transform object and add it into
   // the scene graph.
   Transform3D yAxis = new Transform3D();
   Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
       4000, 0, 0, 0, 0, 0);
   RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,
       objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   rotator.setSchedulingBounds(bounds);
   objTrans.addChild(rotator);
   // Have Java 3D perform optimizations on this scene graph.
   objRoot.rupile();
   return objRoot;
 }
 /*
  * Create the geometry to add to the platform geometry.
  */
 PlatformGeometry createAimer() {
   PlatformGeometry pg = new PlatformGeometry();
   // This TransformGroup will be used by the MouseTranslate
   // utiltiy to move the cylinder around the canvas. when the
   // the user holds down mouse button 3.
   TransformGroup moveTG = new TransformGroup();
   moveTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
   moveTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   MouseTranslate mouseT = new MouseTranslate(moveTG);
   moveTG.addChild(mouseT);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   mouseT.setSchedulingBounds(bounds);
   pg.addChild(moveTG);
   // This TransformGroup is used to place the cylinder in the scene.
   // The cylinder will be rotated 90 degrees so it will appear as
   // a circle on the screen (could be made into a nice gun site...).
   // The cylinder is also displaced a little in Z so it is in front
   // of the viewer.
   Transform3D xForm = new Transform3D();
   xForm.rotX(Math.PI / 2.0);
   xForm.setTranslation(new Vector3d(0.0, 0.0, -0.7));
   TransformGroup placementTG = new TransformGroup(xForm);
   moveTG.addChild(placementTG);
   // Create the cylinder - make it thin and transparent.
   Appearance cylinderAppearance = new Appearance();
   TransparencyAttributes transAttrs = new TransparencyAttributes(
       TransparencyAttributes.FASTEST, 0.5f);
   //        cylinderAppearance.setTransparencyAttributes(transAttrs);
   Cylinder aimer = new Cylinder(0.06f, 0.005f, 0, cylinderAppearance);
   placementTG.addChild(aimer);
   return pg;
 }
 public void init() {
   setLayout(new BorderLayout());
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   Canvas3D c = new Canvas3D(config);
   add("Center", c);
   // Create a simple scene and attach it to the virtual universe
   BranchGroup scene = createSceneGraph();
   u = new SimpleUniverse(c);
   PlatformGeometry pg = createAimer();
   // Now set the just created PlatformGeometry.
   ViewingPlatform vp = u.getViewingPlatform();
   vp.setPlatformGeometry(pg);
   // This will move the ViewPlatform back a bit so the
   // objects in the scene can be viewed.
   u.getViewingPlatform().setNominalViewingTransform();
   // Add everthing to the scene graph - it will now be displayed.
   u.addBranchGraph(scene);
 }
 public SimpleGeometry(String[] args) {
 }
 public SimpleGeometry() {
 }
 public void destroy() {
   u.cleanup();
 }
 public static void main(String[] args) {
   new MainFrame(new SimpleGeometry(args), 256, 256);
 }

}


      </source>
   
  
 
  



Example Appearance

   <source lang="java">

/*

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

import java.applet.Applet; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.CheckboxMenuItem; import java.awt.ruponent; import java.awt.Cursor; import java.awt.Frame; import java.awt.Menu; import java.awt.MenuBar; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.util.Enumeration; import java.util.EventListener; 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.Group; import javax.media.j3d.Light; import javax.media.j3d.LineAttributes; import javax.media.j3d.Material; import javax.media.j3d.PointAttributes; import javax.media.j3d.PolygonAttributes; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Shape3D; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TransparencyAttributes; import javax.media.j3d.TriangleArray; import javax.media.j3d.WakeupCriterion; import javax.media.j3d.WakeupOnAWTEvent; import javax.media.j3d.WakeupOnElapsedFrames; import javax.media.j3d.WakeupOr; import javax.vecmath.Color3f; import javax.vecmath.Matrix4d; 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.image.TextureLoader; import com.sun.j3d.utils.universe.PlatformGeometry; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.Viewer; import com.sun.j3d.utils.universe.ViewingPlatform; public class ExAppearance extends Java3DFrame {

 //--------------------------------------------------------------
 //  SCENE CONTENT
 //--------------------------------------------------------------
 public Group buildScene() {
   // Turn off the example headlight
   setHeadlightEnable(false);
   // Build the scene group
   Group objRoot = new Group();
   // Set up the global lights
   Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
   Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
   Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   AmbientLight aLgt = new AmbientLight(alColor);
   aLgt.setInfluencingBounds(bounds);
   DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
   lgt1.setInfluencingBounds(bounds);
   objRoot.addChild(aLgt);
   objRoot.addChild(lgt1);
   // Add a background
   Background background = new Background();
   background.setColor(new Color3f(0.0f, 0.5f, 1.0f));
   background.setApplicationBounds(bounds);
   objRoot.addChild(background);
   // Create a bunch of objects with a behavior and add them
   // into the scene graph.
   int row, col;
   Appearance[][] app = new Appearance[3][3];
   for (row = 0; row < 3; row++)
     for (col = 0; col < 3; col++)
       app[row][col] = createAppearance(row * 3 + col);
   for (int i = 0; i < 3; i++) {
     double ypos = (double) (i - 1) * 1.9;
     for (int j = 0; j < 3; j++) {
       double xpos = (double) (j - 1) * 2.1;
       objRoot.addChild(createObject(app[i][j], 1.0, xpos, ypos));
     }
   }
   return objRoot;
 }
 private Appearance createAppearance(int idx) {
   Appearance app = new Appearance();
   // Globally used colors
   Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
   Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
   switch (idx) {
   // Unlit solid
   case 0: {
     // Set up the coloring properties
     Color3f objColor = new Color3f(1.0f, 0.2f, 0.4f);
     ColoringAttributes ca = new ColoringAttributes();
     ca.setColor(objColor);
     app.setColoringAttributes(ca);
     break;
   }
   // Unlit wire frame
   case 1: {
     // Set up the coloring properties
     Color3f objColor = new Color3f(1.0f, 0.2f, 0.4f);
     ColoringAttributes ca = new ColoringAttributes();
     ca.setColor(objColor);
     app.setColoringAttributes(ca);
     // Set up the polygon attributes
     PolygonAttributes pa = new PolygonAttributes();
     pa.setPolygonMode(pa.POLYGON_LINE);
     pa.setCullFace(pa.CULL_NONE);
     app.setPolygonAttributes(pa);
     // Set up line attributes
     LineAttributes lta = new LineAttributes();
     lta.setLineWidth(10.0f);
     app.setLineAttributes(lta);
     break;
   }
   // Unlit points
   case 2: {
     // Set up the coloring properties
     Color3f objColor = new Color3f(1.0f, 0.2f, 0.4f);
     ColoringAttributes ca = new ColoringAttributes();
     ca.setColor(objColor);
     app.setColoringAttributes(ca);
     // Set up the polygon attributes
     PolygonAttributes pa = new PolygonAttributes();
     pa.setPolygonMode(pa.POLYGON_POINT);
     pa.setCullFace(pa.CULL_NONE);
     app.setPolygonAttributes(pa);
     // Set up point attributes
     PointAttributes pta = new PointAttributes();
     pta.setPointSize(10.0f);
     app.setPointAttributes(pta);
     break;
   }
   // Lit solid
   case 3: {
     // Set up the material properties
     Color3f objColor = new Color3f(0.8f, 0.0f, 0.0f);
     app.setMaterial(new Material(objColor, black, objColor, white,
         80.0f));
     break;
   }
   // Texture mapped, lit solid
   case 4: {
     // Set up the texture map
     TextureLoader tex = new TextureLoader("apimage.jpg", this);
     app.setTexture(tex.getTexture());
     // Set up the material properties
     app.setMaterial(new Material(white, black, white, black, 1.0f));
     break;
   }
   // Transparent, lit solid
   case 5: {
     // Set up the transparency properties
     TransparencyAttributes ta = new TransparencyAttributes();
     ta.setTransparencyMode(ta.BLENDED);
     ta.setTransparency(0.6f);
     app.setTransparencyAttributes(ta);
     // Set up the polygon attributes
     PolygonAttributes pa = new PolygonAttributes();
     pa.setCullFace(pa.CULL_NONE);
     app.setPolygonAttributes(pa);
     // Set up the material properties
     Color3f objColor = new Color3f(0.7f, 0.8f, 1.0f);
     app
         .setMaterial(new Material(objColor, black, objColor, black,
             1.0f));
     break;
   }
   // Lit solid, no specular
   case 6: {
     // Set up the material properties
     Color3f objColor = new Color3f(0.0f, 0.0f, 0.8f);
     app.setMaterial(new Material(objColor, black, objColor, black,
         80.0f));
     break;
   }
   // Lit solid, specular only
   case 7: {
     // Set up the material properties
     Color3f objColor = new Color3f(0.8f, 0.0f, 0.0f);
     app.setMaterial(new Material(black, black, black, white, 80.0f));
     break;
   }
   // Another lit solid with a different color
   case 8: {
     // Set up the material properties
     Color3f objColor = new Color3f(0.8f, 0.8f, 0.0f);
     app.setMaterial(new Material(objColor, black, objColor, white,
         80.0f));
     break;
   }
   default: {
     ColoringAttributes ca = new ColoringAttributes();
     ca.setColor(new Color3f(0.0f, 1.0f, 0.0f));
     app.setColoringAttributes(ca);
   }
   }
   return app;
 }
 private Group createObject(Appearance app, double scale, double xpos,
     double ypos) {
   // Create a transform group node to scale and position the object.
   Transform3D t = new Transform3D();
   t.set(scale, new Vector3d(xpos, ypos, 0.0));
   TransformGroup objTrans = new TransformGroup(t);
   // Create a second transform group node and initialize it to the
   // identity. Enable the TRANSFORM_WRITE capability so that
   // our behavior code can modify it at runtime.
   TransformGroup spinTg = new TransformGroup();
   spinTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   // Create a simple shape leaf node and set the appearance
   Shape3D shape = new Tetrahedron();
   shape.setAppearance(app);
   // add it to the scene graph.
   spinTg.addChild(shape);
   // Create a new Behavior object that will perform the desired
   // operation on the specified transform object and add it into
   // the scene graph.
   Transform3D yAxis = new Transform3D();
   Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
       5000, 0, 0, 0, 0, 0);
   RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,
       spinTg, yAxis, 0.0f, (float) Math.PI * 2.0f);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   rotator.setSchedulingBounds(bounds);
   // Add the behavior and the transform group to the object
   objTrans.addChild(rotator);
   objTrans.addChild(spinTg);
   return objTrans;
 }
 //--------------------------------------------------------------
 //  USER INTERFACE
 //--------------------------------------------------------------
 //
 //  Main
 //
 public static void main(String[] args) {
   ExAppearance ex = new ExAppearance();
   ex.initialize(args);
   ex.buildUniverse();
   ex.showFrame();
 }
 //
 //  Initialize the GUI (application and applet)
 //
 public void initialize(String[] args) {
   // Initialize the window, menubar, etc.
   super.initialize(args);
   exampleFrame.setTitle("Java 3D Appearance Example");
 }

} /*

* @(#)Tetrahedron.java 1.13 02/04/01 15:03:14
* 
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*  - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* 
* 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.
* 
* You acknowledge that Software is not designed,licensed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/

class Tetrahedron extends Shape3D {

 private static final float sqrt3 = (float) Math.sqrt(3.0);
 private static final float sqrt3_3 = sqrt3 / 3.0f;
 private static final float sqrt24_3 = (float) Math.sqrt(24.0) / 3.0f;
 private static final float ycenter = 0.5f * sqrt24_3;
 private static final float zcenter = -sqrt3_3;
 private static final Point3f p1 = new Point3f(-1.0f, -ycenter, -zcenter);
 private static final Point3f p2 = new Point3f(1.0f, -ycenter, -zcenter);
 private static final Point3f p3 = new Point3f(0.0f, -ycenter, -sqrt3
     - zcenter);
 private static final Point3f p4 = new Point3f(0.0f, sqrt24_3 - ycenter,
     0.0f);
 private static final Point3f[] verts = { p1, p2, p4, // front face
     p1, p4, p3, // left, back face
     p2, p3, p4, // right, back face
     p1, p3, p2, // bottom face
 };
 private TexCoord2f texCoord[] = { new TexCoord2f(0.0f, 0.0f),
     new TexCoord2f(1.0f, 0.0f), new TexCoord2f(0.5f, sqrt3 / 2.0f), };
 public Tetrahedron() {
   int i;
   TriangleArray tetra = new TriangleArray(12, TriangleArray.COORDINATES
       | TriangleArray.NORMALS | TriangleArray.TEXTURE_COORDINATE_2);
   tetra.setCoordinates(0, verts);
   for (i = 0; i < 12; i++) {
     tetra.setTextureCoordinate(0, i, texCoord[i % 3]);
   }
   int face;
   Vector3f normal = new Vector3f();
   Vector3f v1 = new Vector3f();
   Vector3f v2 = new Vector3f();
   Point3f[] pts = new Point3f[3];
   for (i = 0; i < 3; i++)
     pts[i] = new Point3f();
   for (face = 0; face < 4; face++) {
     tetra.getCoordinates(face * 3, pts);
     v1.sub(pts[1], pts[0]);
     v2.sub(pts[2], pts[0]);
     normal.cross(v1, v2);
     normal.normalize();
     for (i = 0; i < 3; i++) {
       tetra.setNormal((face * 3 + i), normal);
     }
   }
   this.setGeometry(tetra);
   this.setAppearance(new Appearance());
 }

} /**

* The Example class is a base class extended by example applications. The class
* provides basic features to create a top-level frame, add a menubar and
* Canvas3D, build the universe, set up "examine" and "walk" style navigation
* behaviors, and provide hooks so that subclasses can add 3D content to the
* example"s universe.
*

* Using this Example class simplifies the construction of example applications, * enabling the author to focus upon 3D content and not the busywork of creating * windows, menus, and universes. * * @version 1.0, 98/04/16 * @author David R. Nadeau, San Diego Supercomputer Center */ class Java3DFrame extends Applet implements WindowListener, ActionListener, ItemListener, CheckboxMenuListener { // Navigation types public final static int Walk = 0; public final static int Examine = 1; // Should the scene be compiled? private boolean shouldCompile = true; // GUI objects for our subclasses protected Java3DFrame example = null; protected Frame exampleFrame = null; protected MenuBar exampleMenuBar = null; protected Canvas3D exampleCanvas = null; protected TransformGroup exampleViewTransform = null; protected TransformGroup exampleSceneTransform = null; protected boolean debug = false; // Private GUI objects and state private boolean headlightOnOff = true; private int navigationType = Examine; private CheckboxMenuItem headlightMenuItem = null; private CheckboxMenuItem walkMenuItem = null; private CheckboxMenuItem examineMenuItem = null; private DirectionalLight headlight = null; private ExamineViewerBehavior examineBehavior = null; private WalkViewerBehavior walkBehavior = null; //-------------------------------------------------------------- // ADMINISTRATION //-------------------------------------------------------------- /** * The main program entry point when invoked as an application. Each example * application that extends this class must define their own main. * * @param args * a String array of command-line arguments */ public static void main(String[] args) { Java3DFrame ex = new Java3DFrame(); ex.initialize(args); ex.buildUniverse(); ex.showFrame(); } /** * Constructs a new Example object. * * @return a new Example that draws no 3D content */ public Java3DFrame() { // Do nothing } /** * Initializes the application when invoked as an applet. */ public void init() { // Collect properties into String array String[] args = new String[2]; // NOTE: to be done still... this.initialize(args); this.buildUniverse(); this.showFrame(); // NOTE: add something to the browser page? } /** * Initializes the Example by parsing command-line arguments, building an * AWT Frame, constructing a menubar, and creating the 3D canvas. * * @param args * a String array of command-line arguments */ protected void initialize(String[] args) { example = this; // Parse incoming arguments parseArgs(args); // Build the frame if (debug) System.err.println("Building GUI..."); exampleFrame = new Frame(); exampleFrame.setSize(640, 480); exampleFrame.setTitle("Java 3D Example"); exampleFrame.setLayout(new BorderLayout()); // Set up a close behavior exampleFrame.addWindowListener(this); // Create a canvas exampleCanvas = new Canvas3D(null); exampleCanvas.setSize(630, 460); exampleFrame.add("Center", exampleCanvas); // Build the menubar exampleMenuBar = this.buildMenuBar(); exampleFrame.setMenuBar(exampleMenuBar); // Pack exampleFrame.pack(); exampleFrame.validate(); // exampleFrame.setVisible( true ); } /** * Parses incoming command-line arguments. Applications that subclass this * class may override this method to support their own command-line * arguments. * * @param args * a String array of command-line arguments */ protected void parseArgs(String[] args) { for (int i = 0; i < args.length; i++) { if (args[i].equals("-d")) debug = true; } } //-------------------------------------------------------------- // SCENE CONTENT //-------------------------------------------------------------- /** * Builds the 3D universe by constructing a virtual universe (via * SimpleUniverse), a view platform (via SimpleUniverse), and a view (via * SimpleUniverse). A headlight is added and a set of behaviors initialized * to handle navigation types. */ protected void buildUniverse() { // // Create a SimpleUniverse object, which builds: // // - a Locale using the given hi-res coordinate origin // // - a ViewingPlatform which in turn builds: // - a MultiTransformGroup with which to move the // the ViewPlatform about // // - a ViewPlatform to hold the view // // - a BranchGroup to hold avatar geometry (if any) // // - a BranchGroup to hold view platform // geometry (if any) // // - a Viewer which in turn builds: // - a PhysicalBody which characterizes the user"s // viewing preferences and abilities // // - a PhysicalEnvironment which characterizes the // user"s rendering hardware and software // // - a JavaSoundMixer which initializes sound // support within the 3D environment // // - a View which renders the scene into a Canvas3D // // All of these actions could be done explicitly, but // using the SimpleUniverse utilities simplifies the code. // if (debug) System.err.println("Building scene graph..."); SimpleUniverse universe = new SimpleUniverse(null, // Hi-res coordinate // for the origin - // use default 1, // Number of transforms in MultiTransformGroup exampleCanvas, // Canvas3D into which to draw null); // URL for user configuration file - use defaults // // Get the viewer and create an audio device so that // sound will be enabled in this content. // Viewer viewer = universe.getViewer(); viewer.createAudioDevice(); // // Get the viewing platform created by SimpleUniverse. // From that platform, get the inner-most TransformGroup // in the MultiTransformGroup. That inner-most group // contains the ViewPlatform. It is this inner-most // TransformGroup we need in order to: // // - add a "headlight" that always aims forward from // the viewer // // - change the viewing direction in a "walk" style // // The inner-most TransformGroup"s transform will be // changed by the walk behavior (when enabled). // ViewingPlatform viewingPlatform = universe.getViewingPlatform(); exampleViewTransform = viewingPlatform.getViewPlatformTransform(); // // Create a "headlight" as a forward-facing directional light. // Set the light"s bounds to huge. Since we want the light // on the viewer"s "head", we need the light within the // TransformGroup containing the ViewPlatform. The // ViewingPlatform class creates a handy hook to do this // called "platform geometry". The PlatformGeometry class is // subclassed off of BranchGroup, and is intended to contain // a description of the 3D platform itself... PLUS a headlight! // So, to add the headlight, create a new PlatformGeometry group, // add the light to it, then add that platform geometry to the // ViewingPlatform. // BoundingSphere allBounds = new BoundingSphere( new Point3d(0.0, 0.0, 0.0), 100000.0); PlatformGeometry pg = new PlatformGeometry(); headlight = new DirectionalLight(); headlight.setColor(White); headlight.setDirection(new Vector3f(0.0f, 0.0f, -1.0f)); headlight.setInfluencingBounds(allBounds); headlight.setCapability(Light.ALLOW_STATE_WRITE); pg.addChild(headlight); viewingPlatform.setPlatformGeometry(pg); // // Create the 3D content BranchGroup, containing: // // - a TransformGroup who"s transform the examine behavior // will change (when enabled). // // - 3D geometry to view // // Build the scene root BranchGroup sceneRoot = new BranchGroup(); // Build a transform that we can modify exampleSceneTransform = new TransformGroup(); exampleSceneTransform .setCapability(TransformGroup.ALLOW_TRANSFORM_READ); exampleSceneTransform .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); exampleSceneTransform.setCapability(Group.ALLOW_CHILDREN_EXTEND); // // Build the scene, add it to the transform, and add // the transform to the scene root // if (debug) System.err.println(" scene..."); Group scene = this.buildScene(); exampleSceneTransform.addChild(scene); sceneRoot.addChild(exampleSceneTransform); // // Create a pair of behaviors to implement two navigation // types: // // - "examine": a style where mouse drags rotate about // the scene"s origin as if it is an object under // examination. This is similar to the "Examine" // navigation type used by VRML browsers. // // - "walk": a style where mouse drags rotate about // the viewer"s center as if the viewer is turning // about to look at a scene they are in. This is // similar to the "Walk" navigation type used by // VRML browsers. // // Aim the examine behavior at the scene"s TransformGroup // and add the behavior to the scene root. // // Aim the walk behavior at the viewing platform"s // TransformGroup and add the behavior to the scene root. // // Enable one (and only one!) of the two behaviors // depending upon the current navigation type. // examineBehavior = new ExamineViewerBehavior(exampleSceneTransform, // Transform // gorup // to // modify exampleFrame); // Parent frame for cusor changes examineBehavior.setSchedulingBounds(allBounds); sceneRoot.addChild(examineBehavior); walkBehavior = new WalkViewerBehavior(exampleViewTransform, // Transform // group to // modify exampleFrame); // Parent frame for cusor changes walkBehavior.setSchedulingBounds(allBounds); sceneRoot.addChild(walkBehavior); if (navigationType == Walk) { examineBehavior.setEnable(false); walkBehavior.setEnable(true); } else { examineBehavior.setEnable(true); walkBehavior.setEnable(false); } // // Compile the scene branch group and add it to the // SimpleUniverse. // if (shouldCompile) sceneRoot.rupile(); universe.addBranchGraph(sceneRoot); reset(); } /** * Builds the scene. Example application subclasses should replace this * method with their own method to build 3D content. * * @return a Group containing 3D content to display */ public Group buildScene() { // Build the scene group containing nothing Group scene = new Group(); return scene; } //-------------------------------------------------------------- // SET/GET METHODS //-------------------------------------------------------------- /** * Sets the headlight on/off state. The headlight faces forward in the * direction the viewer is facing. Example applications that add their own * lights will typically turn the headlight off. A standard menu item * enables the headlight to be turned on and off via user control. * * @param onOff * a boolean turning the light on (true) or off (false) */ public void setHeadlightEnable(boolean onOff) { headlightOnOff = onOff; if (headlight != null) headlight.setEnable(headlightOnOff); if (headlightMenuItem != null) headlightMenuItem.setState(headlightOnOff); } /** * Gets the headlight on/off state. * * @return a boolean indicating if the headlight is on or off */ public boolean getHeadlightEnable() { return headlightOnOff; } /** * Sets the navigation type to be either Examine or Walk. The Examine * navigation type sets up behaviors that use mouse drags to rotate and * translate scene content as if it is an object held at arm"s length and * under examination. The Walk navigation type uses mouse drags to rotate * and translate the viewer as if they are walking through the content. The * Examine type is the default. * * @param nav * either Walk or Examine */ public void setNavigationType(int nav) { if (nav == Walk) { navigationType = Walk; if (walkMenuItem != null) walkMenuItem.setState(true); if (examineMenuItem != null) examineMenuItem.setState(false); if (walkBehavior != null) walkBehavior.setEnable(true); if (examineBehavior != null) examineBehavior.setEnable(false); } else { navigationType = Examine; if (walkMenuItem != null) walkMenuItem.setState(false); if (examineMenuItem != null) examineMenuItem.setState(true); if (walkBehavior != null) walkBehavior.setEnable(false); if (examineBehavior != null) examineBehavior.setEnable(true); } } /** * Gets the current navigation type, returning either Walk or Examine. * * @return either Walk or Examine */ public int getNavigationType() { return navigationType; } /** * Sets whether the scene graph should be compiled or not. Normally this is * always a good idea. For some example applications that use this Example * framework, it is useful to disable compilation - particularly when nodes * and node components will need to be made un-live in order to make * changes. Once compiled, such components can be made un-live, but they are * still unchangable unless appropriate capabilities have been set. * * @param onOff * a boolean turning compilation on (true) or off (false) */ public void setCompilable(boolean onOff) { shouldCompile = onOff; } /** * Gets whether the scene graph will be compiled or not. * * @return a boolean indicating if scene graph compilation is on or off */ public boolean getCompilable() { return shouldCompile; } //These methods will be replaced // Set the view position and direction public void setViewpoint(Point3f position, Vector3f direction) { Transform3D t = new Transform3D(); t.set(new Vector3f(position)); exampleViewTransform.setTransform(t); // how to set direction? } // Reset transforms public void reset() { Transform3D trans = new Transform3D(); exampleSceneTransform.setTransform(trans); trans.set(new Vector3f(0.0f, 0.0f, 10.0f)); exampleViewTransform.setTransform(trans); setNavigationType(navigationType); } // // Gets the URL (with file: prepended) for the current directory. // This is a terrible hack needed in the Alpha release of Java3D // in order to build a full path URL for loading sounds with // MediaContainer. When MediaContainer is fully implemented, // it should handle relative path names, but not yet. // public String getCurrentDirectory() { // Create a bogus file so that we can query it"s path File dummy = new File("dummy.tmp"); String dummyPath = dummy.getAbsolutePath(); // strip "/dummy.tmp" from end of dummyPath and put into "path" if (dummyPath.endsWith(File.separator + "dummy.tmp")) { int index = dummyPath.lastIndexOf(File.separator + "dummy.tmp"); if (index >= 0) { int pathLength = index + 5; // pre-pend "file:" char[] charPath = new char[pathLength]; dummyPath.getChars(0, index, charPath, 5); String path = new String(charPath, 0, pathLength); path = "file:" + path.substring(5, pathLength); return path + File.separator; } } return dummyPath + File.separator; } //-------------------------------------------------------------- // USER INTERFACE //-------------------------------------------------------------- /** * Builds the example AWT Frame menubar. Standard menus and their options * are added. Applications that subclass this class should build their * menubar additions within their initialize method. * * @return a MenuBar for the AWT Frame */ private MenuBar buildMenuBar() { // Build the menubar MenuBar menuBar = new MenuBar(); // File menu Menu m = new Menu("File"); m.addActionListener(this); m.add("Exit"); menuBar.add(m); // View menu m = new Menu("View"); m.addActionListener(this); m.add("Reset view"); m.addSeparator(); walkMenuItem = new CheckboxMenuItem("Walk"); walkMenuItem.addItemListener(this); m.add(walkMenuItem); examineMenuItem = new CheckboxMenuItem("Examine"); examineMenuItem.addItemListener(this); m.add(examineMenuItem); if (navigationType == Walk) { walkMenuItem.setState(true); examineMenuItem.setState(false); } else { walkMenuItem.setState(false); examineMenuItem.setState(true); } m.addSeparator(); headlightMenuItem = new CheckboxMenuItem("Headlight on/off"); headlightMenuItem.addItemListener(this); headlightMenuItem.setState(headlightOnOff); m.add(headlightMenuItem); menuBar.add(m); return menuBar; } /** * Shows the application"s frame, making it and its menubar, 3D canvas, and * 3D content visible. */ public void showFrame() { exampleFrame.show(); } /** * Quits the application. */ public void quit() { System.exit(0); } /** * Handles menu selections. * * @param event * an ActionEvent indicating what menu action requires handling */ public void actionPerformed(ActionEvent event) { String arg = event.getActionCommand(); if (arg.equals("Reset view")) reset(); else if (arg.equals("Exit")) quit(); } /** * Handles checkbox items on a CheckboxMenu. The Example class has none of * its own, but subclasses may have some. * * @param menu * which CheckboxMenu needs action * @param check * which CheckboxMenu item has changed */ public void checkboxChanged(CheckboxMenu menu, int check) { // None for us } /** * Handles on/off checkbox items on a standard menu. * * @param event * an ItemEvent indicating what requires handling */ public void itemStateChanged(ItemEvent event) { Object src = event.getSource(); boolean state; if (src == headlightMenuItem) { state = headlightMenuItem.getState(); headlight.setEnable(state); } else if (src == walkMenuItem) setNavigationType(Walk); else if (src == examineMenuItem) setNavigationType(Examine); } /** * Handles a window closing event notifying the application that the user * has chosen to close the application without selecting the "Exit" menu * item. * * @param event * a WindowEvent indicating the window is closing */ public void windowClosing(WindowEvent event) { quit(); } public void windowClosed(WindowEvent event) { } public void windowOpened(WindowEvent event) { } public void windowIconified(WindowEvent event) { } public void windowDeiconified(WindowEvent event) { } public void windowActivated(WindowEvent event) { } public void windowDeactivated(WindowEvent event) { } // Well known colors, positions, and directions public final static Color3f White = new Color3f(1.0f, 1.0f, 1.0f); public final static Color3f Gray = new Color3f(0.7f, 0.7f, 0.7f); public final static Color3f DarkGray = new Color3f(0.2f, 0.2f, 0.2f); public final static Color3f Black = new Color3f(0.0f, 0.0f, 0.0f); public final static Color3f Red = new Color3f(1.0f, 0.0f, 0.0f); public final static Color3f DarkRed = new Color3f(0.3f, 0.0f, 0.0f); public final static Color3f Yellow = new Color3f(1.0f, 1.0f, 0.0f); public final static Color3f DarkYellow = new Color3f(0.3f, 0.3f, 0.0f); public final static Color3f Green = new Color3f(0.0f, 1.0f, 0.0f); public final static Color3f DarkGreen = new Color3f(0.0f, 0.3f, 0.0f); public final static Color3f Cyan = new Color3f(0.0f, 1.0f, 1.0f); public final static Color3f Blue = new Color3f(0.0f, 0.0f, 1.0f); public final static Color3f DarkBlue = new Color3f(0.0f, 0.0f, 0.3f); public final static Color3f Magenta = new Color3f(1.0f, 0.0f, 1.0f); public final static Vector3f PosX = new Vector3f(1.0f, 0.0f, 0.0f); public final static Vector3f NegX = new Vector3f(-1.0f, 0.0f, 0.0f); public final static Vector3f PosY = new Vector3f(0.0f, 1.0f, 0.0f); public final static Vector3f NegY = new Vector3f(0.0f, -1.0f, 0.0f); public final static Vector3f PosZ = new Vector3f(0.0f, 0.0f, 1.0f); public final static Vector3f NegZ = new Vector3f(0.0f, 0.0f, -1.0f); public final static Point3f Origin = new Point3f(0.0f, 0.0f, 0.0f); public final static Point3f PlusX = new Point3f(0.75f, 0.0f, 0.0f); public final static Point3f MinusX = new Point3f(-0.75f, 0.0f, 0.0f); public final static Point3f PlusY = new Point3f(0.0f, 0.75f, 0.0f); public final static Point3f MinusY = new Point3f(0.0f, -0.75f, 0.0f); public final static Point3f PlusZ = new Point3f(0.0f, 0.0f, 0.75f); public final static Point3f MinusZ = new Point3f(0.0f, 0.0f, -0.75f); } // //INTERFACE //CheckboxMenuListener - listen for checkbox change events // //DESCRIPTION //The checkboxChanged method is called by users of this class //to notify the listener when a checkbox choice has changed on //a CheckboxMenu class menu. // interface CheckboxMenuListener extends EventListener { public void checkboxChanged(CheckboxMenu menu, int check); } /** * ExamineViewerBehavior * * @version 1.0, 98/04/16 */ /** * Wakeup on mouse button presses, releases, and mouse movements and generate * transforms in an "examination style" that enables the user to rotate, * translation, and zoom an object as if it is held at arm"s length. Such an * examination style is similar to the "Examine" navigation type used by VRML * browsers. * * The behavior maps mouse drags to different transforms depending upon the * mosue button held down: * * Button 1 (left) Horizontal movement --> Y-axis rotation Vertical movement --> * X-axis rotation * * Button 2 (middle) Horizontal movement --> nothing Vertical movement --> * Z-axis translation * * Button 3 (right) Horizontal movement --> X-axis translation Vertical movement * --> Y-axis translation * * To support systems with 2 or 1 mouse buttons, the following alternate * mappings are supported while dragging with any mouse button held down and * zero or more keyboard modifiers held down: * * No modifiers = Button 1 ALT = Button 2 Meta = Button 3 Control = Button 3 * * The behavior automatically modifies a TransformGroup provided to the * constructor. The TransformGroup"s transform can be set at any time by the * application or other behaviors to cause the examine rotation and translation * to be reset. */ // This class is inspired by the MouseBehavior, MouseRotate, // MouseTranslate, and MouseZoom utility behaviors provided with // Java 3D. This class differs from those utilities in that it: // // (a) encapsulates all three behaviors into one in order to // enforce a specific "Examine" symantic // // (b) supports set/get of the rotation and translation factors // that control the speed of movement. // // (c) supports the "Control" modifier as an alternative to the // "Meta" modifier not present on PC, Mac, and most non-Sun // keyboards. This makes button3 behavior usable on PCs, // Macs, and other systems with fewer than 3 mouse buttons. class ExamineViewerBehavior extends ViewerBehavior { // Previous cursor location protected int previousX = 0; protected int previousY = 0; // Saved standard cursor protected Cursor savedCursor = null; /** * Construct an examine behavior that listens to mouse movement and button * presses to generate rotation and translation transforms written into a * transform group given later with the setTransformGroup( ) method. */ public ExamineViewerBehavior() { super(); } /** * Construct an examine behavior that listens to mouse movement and button * presses to generate rotation and translation transforms written into a * transform group given later with the setTransformGroup( ) method. * * @param parent * The AWT Component that contains the area generating mouse * events. */ public ExamineViewerBehavior(Component parent) { super(parent); } /** * Construct an examine behavior that listens to mouse movement and button * presses to generate rotation and translation transforms written into the * given transform group. * * @param transformGroup * The transform group to be modified by the behavior. */ public ExamineViewerBehavior(TransformGroup transformGroup) { super(); subjectTransformGroup = transformGroup; } /** * Construct an examine behavior that listens to mouse movement and button * presses to generate rotation and translation transforms written into the * given transform group. * * @param transformGroup * The transform group to be modified by the behavior. * @param parent * The AWT Component that contains the area generating mouse * events. */ public ExamineViewerBehavior(TransformGroup transformGroup, Component parent) { super(parent); subjectTransformGroup = transformGroup; } /** * Respond to a button1 event (press, release, or drag). * * @param mouseEvent * A MouseEvent to respond to. */ public void onButton1(MouseEvent mev) { if (subjectTransformGroup == null) return; int x = mev.getX(); int y = mev.getY(); if (mev.getID() == MouseEvent.MOUSE_PRESSED) { // Mouse button pressed: record position previousX = x; previousY = y; // Change to a "move" cursor if (parentComponent != null) { savedCursor = parentComponent.getCursor(); parentComponent.setCursor(Cursor .getPredefinedCursor(Cursor.HAND_CURSOR)); } return; } if (mev.getID() == MouseEvent.MOUSE_RELEASED) { // Mouse button released: do nothing // Switch the cursor back if (parentComponent != null) parentComponent.setCursor(savedCursor); return; } // // Mouse moved while button down: create a rotation // // Compute the delta in X and Y from the previous // position. Use the delta to compute rotation // angles with the mapping: // // positive X mouse delta --> positive Y-axis rotation // positive Y mouse delta --> positive X-axis rotation // // where positive X mouse movement is to the right, and // positive Y mouse movement is **down** the screen. // int deltaX = x - previousX; int deltaY = y - previousY; if (deltaX > UNUSUAL_XDELTA || deltaX < -UNUSUAL_XDELTA || deltaY > UNUSUAL_YDELTA || deltaY < -UNUSUAL_YDELTA) { // Deltas are too huge to be believable. Probably a glitch. // Don"t record the new XY location, or do anything. return; } double xRotationAngle = deltaY * XRotationFactor; double yRotationAngle = deltaX * YRotationFactor; // // Build transforms // transform1.rotX(xRotationAngle); transform2.rotY(yRotationAngle); // Get and save the current transform matrix subjectTransformGroup.getTransform(currentTransform); currentTransform.get(matrix); translate.set(matrix.m03, matrix.m13, matrix.m23); // Translate to the origin, rotate, then translate back currentTransform.setTranslation(origin); currentTransform.mul(transform1, currentTransform); currentTransform.mul(transform2, currentTransform); currentTransform.setTranslation(translate); // Update the transform group subjectTransformGroup.setTransform(currentTransform); previousX = x; previousY = y; } /** * Respond to a button2 event (press, release, or drag). * * @param mouseEvent * A MouseEvent to respond to. */ public void onButton2(MouseEvent mev) { if (subjectTransformGroup == null) return; int x = mev.getX(); int y = mev.getY(); if (mev.getID() == MouseEvent.MOUSE_PRESSED) { // Mouse button pressed: record position previousX = x; previousY = y; // Change to a "move" cursor if (parentComponent != null) { savedCursor = parentComponent.getCursor(); parentComponent.setCursor(Cursor .getPredefinedCursor(Cursor.MOVE_CURSOR)); } return; } if (mev.getID() == MouseEvent.MOUSE_RELEASED) { // Mouse button released: do nothing // Switch the cursor back if (parentComponent != null) parentComponent.setCursor(savedCursor); return; } // // Mouse moved while button down: create a translation // // Compute the delta in Y from the previous // position. Use the delta to compute translation // distances with the mapping: // // positive Y mouse delta --> positive Y-axis translation // // where positive X mouse movement is to the right, and // positive Y mouse movement is **down** the screen. // int deltaY = y - previousY; if (deltaY > UNUSUAL_YDELTA || deltaY < -UNUSUAL_YDELTA) { // Deltas are too huge to be believable. Probably a glitch. // Don"t record the new XY location, or do anything. return; } double zTranslationDistance = deltaY * ZTranslationFactor; // // Build transforms // translate.set(0.0, 0.0, zTranslationDistance); transform1.set(translate); // Get and save the current transform subjectTransformGroup.getTransform(currentTransform); // Translate as needed currentTransform.mul(transform1, currentTransform); // Update the transform group subjectTransformGroup.setTransform(currentTransform); previousX = x; previousY = y; } /** * Respond to a button3 event (press, release, or drag). * * @param mouseEvent * A MouseEvent to respond to. */ public void onButton3(MouseEvent mev) { if (subjectTransformGroup == null) return; int x = mev.getX(); int y = mev.getY(); if (mev.getID() == MouseEvent.MOUSE_PRESSED) { // Mouse button pressed: record position previousX = x; previousY = y; // Change to a "move" cursor if (parentComponent != null) { savedCursor = parentComponent.getCursor(); parentComponent.setCursor(Cursor .getPredefinedCursor(Cursor.MOVE_CURSOR)); } return; } if (mev.getID() == MouseEvent.MOUSE_RELEASED) { // Mouse button released: do nothing // Switch the cursor back if (parentComponent != null) parentComponent.setCursor(savedCursor); return; } // // Mouse moved while button down: create a translation // // Compute the delta in X and Y from the previous // position. Use the delta to compute translation // distances with the mapping: // // positive X mouse delta --> positive X-axis translation // positive Y mouse delta --> negative Y-axis translation // // where positive X mouse movement is to the right, and // positive Y mouse movement is **down** the screen. // int deltaX = x - previousX; int deltaY = y - previousY; if (deltaX > UNUSUAL_XDELTA || deltaX < -UNUSUAL_XDELTA || deltaY > UNUSUAL_YDELTA || deltaY < -UNUSUAL_YDELTA) { // Deltas are too huge to be believable. Probably a glitch. // Don"t record the new XY location, or do anything. return; } double xTranslationDistance = deltaX * XTranslationFactor; double yTranslationDistance = -deltaY * YTranslationFactor; // // Build transforms // translate.set(xTranslationDistance, yTranslationDistance, 0.0); transform1.set(translate); // Get and save the current transform subjectTransformGroup.getTransform(currentTransform); // Translate as needed currentTransform.mul(transform1, currentTransform); // Update the transform group subjectTransformGroup.setTransform(currentTransform); previousX = x; previousY = y; } /** * Respond to an elapsed frames event (assuming subclass has set up a wakeup * criterion for it). * * @param time * A WakeupOnElapsedFrames criterion to respond to. */ public void onElapsedFrames(WakeupOnElapsedFrames timeEvent) { // Can"t happen } } /* * * Copyright (c) 1998 David R. Nadeau * */ /** * WalkViewerBehavior is a utility class that creates a "walking style" * navigation symantic. * * The behavior wakes up on mouse button presses, releases, and mouse movements * and generates transforms in a "walk style" that enables the user to walk * through a scene, translating and turning about as if they are within the * scene. Such a walk style is similar to the "Walk" navigation type used by * VRML browsers. * <P> * The behavior maps mouse drags to different transforms depending upon the * mouse button held down: *

*
Button 1 (left) *
Horizontal movement --> Y-axis rotation *
Vertical movement --> Z-axis translation * *
Button 2 (middle) *
Horizontal movement --> Y-axis rotation *
Vertical movement --> X-axis rotation * *
Button 3 (right) *
Horizontal movement --> X-axis translation *
Vertical movement --> Y-axis translation *
* 
* To support systems with 2 or 1 mouse buttons, the following alternate
* mappings are supported while dragging with any mouse button held down and
* zero or more keyboard modifiers held down:
*
    *
  • No modifiers = Button 1 *
  • ALT = Button 2 *
  • Meta = Button 3 *
  • Control = Button 3 *
* The behavior automatically modifies a TransformGroup provided to the
* constructor. The TransformGroup"s transform can be set at any time by the
* application or other behaviors to cause the walk rotation and translation to
* be reset.
* <P>
* While a mouse button is down, the behavior automatically changes the cursor
* in a given parent AWT Component. If no parent Component is given, no cursor
* changes are attempted.
* 
* @version 1.0, 98/04/16
* @author David R. Nadeau, San Diego Supercomputer Center
*/

class WalkViewerBehavior extends ViewerBehavior {

 // This class is inspired by the MouseBehavior, MouseRotate,
 // MouseTranslate, and MouseZoom utility behaviors provided with
 // Java 3D. This class differs from those utilities in that it:
 //
 //    (a) encapsulates all three behaviors into one in order to
 //        enforce a specific "Walk" symantic
 //
 //    (b) supports set/get of the rotation and translation factors
 //        that control the speed of movement.
 //
 //    (c) supports the "Control" modifier as an alternative to the
 //        "Meta" modifier not present on PC, Mac, and most non-Sun
 //        keyboards. This makes button3 behavior usable on PCs,
 //        Macs, and other systems with fewer than 3 mouse buttons.
 // Previous and initial cursor locations
 protected int previousX = 0;
 protected int previousY = 0;
 protected int initialX = 0;
 protected int initialY = 0;
 // Deadzone size (delta from initial XY for which no
 // translate or rotate action is taken
 protected static final int DELTAX_DEADZONE = 10;
 protected static final int DELTAY_DEADZONE = 10;
 // Keep a set of wakeup criterion for animation-generated
 // event types.
 protected WakeupCriterion[] mouseAndAnimationEvents = null;
 protected WakeupOr mouseAndAnimationCriterion = null;
 protected WakeupOr savedMouseCriterion = null;
 // Saved standard cursor
 protected Cursor savedCursor = null;
 /**
  * Default Rotation and translation scaling factors for animated movements
  * (Button 1 press).
  */
 public static final double DEFAULT_YROTATION_ANIMATION_FACTOR = 0.0002;
 public static final double DEFAULT_ZTRANSLATION_ANIMATION_FACTOR = 0.01;
 protected double YRotationAnimationFactor = DEFAULT_YROTATION_ANIMATION_FACTOR;
 protected double ZTranslationAnimationFactor = DEFAULT_ZTRANSLATION_ANIMATION_FACTOR;
 /**
  * Constructs a new walk behavior that converts mouse actions into rotations
  * and translations. Rotations and translations are written into a
  * TransformGroup that must be set using the setTransformGroup method. The
  * cursor will be changed during mouse actions if the parent frame is set
  * using the setParentComponent method.
  * 
  * @return a new WalkViewerBehavior that needs its TransformGroup and parent
  *         Component set
  */
 public WalkViewerBehavior() {
   super();
 }
 /**
  * Constructs a new walk behavior that converts mouse actions into rotations
  * and translations. Rotations and translations are written into a
  * TransformGroup that must be set using the setTransformGroup method. The
  * cursor will be changed within the given AWT parent Component during mouse
  * drags.
  * 
  * @param parent
  *            a parent AWT Component within which the cursor will change
  *            during mouse drags
  * 
  * @return a new WalkViewerBehavior that needs its TransformGroup and parent
  *         Component set
  */
 public WalkViewerBehavior(Component parent) {
   super(parent);
 }
 /**
  * Constructs a new walk behavior that converts mouse actions into rotations
  * and translations. Rotations and translations are written into the given
  * TransformGroup. The cursor will be changed during mouse actions if the
  * parent frame is set using the setParentComponent method.
  * 
  * @param transformGroup
  *            a TransformGroup whos transform is read and written by the
  *            behavior
  * 
  * @return a new WalkViewerBehavior that needs its TransformGroup and parent
  *         Component set
  */
 public WalkViewerBehavior(TransformGroup transformGroup) {
   super();
   subjectTransformGroup = transformGroup;
 }
 /**
  * Constructs a new walk behavior that converts mouse actions into rotations
  * and translations. Rotations and translations are written into the given
  * TransformGroup. The cursor will be changed within the given AWT parent
  * Component during mouse drags.
  * 
  * @param transformGroup
  *            a TransformGroup whos transform is read and written by the
  *            behavior
  * 
  * @param parent
  *            a parent AWT Component within which the cursor will change
  *            during mouse drags
  * 
  * @return a new WalkViewerBehavior that needs its TransformGroup and parent
  *         Component set
  */
 public WalkViewerBehavior(TransformGroup transformGroup, Component parent) {
   super(parent);
   subjectTransformGroup = transformGroup;
 }
 /**
  * Initializes the behavior.
  */
 public void initialize() {
   super.initialize();
   savedMouseCriterion = mouseCriterion; // from parent class
   mouseAndAnimationEvents = new WakeupCriterion[4];
   mouseAndAnimationEvents[0] = new WakeupOnAWTEvent(
       MouseEvent.MOUSE_DRAGGED);
   mouseAndAnimationEvents[1] = new WakeupOnAWTEvent(
       MouseEvent.MOUSE_PRESSED);
   mouseAndAnimationEvents[2] = new WakeupOnAWTEvent(
       MouseEvent.MOUSE_RELEASED);
   mouseAndAnimationEvents[3] = new WakeupOnElapsedFrames(0);
   mouseAndAnimationCriterion = new WakeupOr(mouseAndAnimationEvents);
   // Don"t use the above criterion until a button 1 down event
 }
 /**
  * Sets the Y rotation animation scaling factor for Y-axis rotations. This
  * scaling factor is used to control the speed of Y rotation when button 1
  * is pressed and dragged.
  * 
  * @param factor
  *            the double Y rotation scaling factor
  */
 public void setYRotationAnimationFactor(double factor) {
   YRotationAnimationFactor = factor;
 }
 /**
  * Gets the current Y animation rotation scaling factor for Y-axis
  * rotations.
  * 
  * @return the double Y rotation scaling factor
  */
 public double getYRotationAnimationFactor() {
   return YRotationAnimationFactor;
 }
 /**
  * Sets the Z animation translation scaling factor for Z-axis translations.
  * This scaling factor is used to control the speed of Z translation when
  * button 1 is pressed and dragged.
  * 
  * @param factor
  *            the double Z translation scaling factor
  */
 public void setZTranslationAnimationFactor(double factor) {
   ZTranslationAnimationFactor = factor;
 }
 /**
  * Gets the current Z animation translation scaling factor for Z-axis
  * translations.
  * 
  * @return the double Z translation scaling factor
  */
 public double getZTranslationAnimationFactor() {
   return ZTranslationAnimationFactor;
 }
 /**
  * Responds to an elapsed frames event. Such an event is generated on every
  * frame while button 1 is held down. On each call, this method computes new
  * Y-axis rotation and Z-axis translation values and writes them to the
  * behavior"s TransformGroup. The translation and rotation amounts are
  * computed based upon the distance between the current cursor location and
  * the cursor location when button 1 was pressed. As this distance
  * increases, the translation or rotation amount increases.
  * 
  * @param time
  *            the WakeupOnElapsedFrames criterion to respond to
  */
 public void onElapsedFrames(WakeupOnElapsedFrames timeEvent) {
   //
   // Time elapsed while button down: create a rotation and
   // a translation.
   //
   // Compute the delta in X and Y from the initial position to
   // the previous position. Multiply the delta times a scaling
   // factor to compute an offset to add to the current translation
   // and rotation. Use the mapping:
   //
   //   positive X mouse delta --> negative Y-axis rotation
   //   positive Y mouse delta --> positive Z-axis translation
   //
   // where positive X mouse movement is to the right, and
   // positive Y mouse movement is **down** the screen.
   //
   if (buttonPressed != BUTTON1)
     return;
   int deltaX = previousX - initialX;
   int deltaY = previousY - initialY;
   double yRotationAngle = -deltaX * YRotationAnimationFactor;
   double zTranslationDistance = deltaY * ZTranslationAnimationFactor;
   //
   // Build transforms
   //
   transform1.rotY(yRotationAngle);
   translate.set(0.0, 0.0, zTranslationDistance);
   // Get and save the current transform matrix
   subjectTransformGroup.getTransform(currentTransform);
   currentTransform.get(matrix);
   // Translate to the origin, rotate, then translate back
   currentTransform.setTranslation(origin);
   currentTransform.mul(transform1, currentTransform);
   // Translate back from the origin by the original translation
   // distance, plus the new walk translation... but force walk
   // to travel on a plane by ignoring the Y component of a
   // transformed translation vector.
   currentTransform.transform(translate);
   translate.x += matrix.m03; // add in existing X translation
   translate.y = matrix.m13; // use Y translation
   translate.z += matrix.m23; // add in existing Z translation
   currentTransform.setTranslation(translate);
   // Update the transform group
   subjectTransformGroup.setTransform(currentTransform);
 }
 /**
  * Responds to a button1 event (press, release, or drag). On a press, the
  * method adds a wakeup criterion to the behavior"s set, callling for the
  * behavior to be awoken on each frame. On a button prelease, this criterion
  * is removed from the set.
  * 
  * @param mouseEvent
  *            the MouseEvent to respond to
  */
 public void onButton1(MouseEvent mev) {
   if (subjectTransformGroup == null)
     return;
   int x = mev.getX();
   int y = mev.getY();
   if (mev.getID() == MouseEvent.MOUSE_PRESSED) {
     // Mouse button pressed: record position and change
     // the wakeup criterion to include elapsed time wakeups
     // so we can animate.
     previousX = x;
     previousY = y;
     initialX = x;
     initialY = y;
     // Swap criterion... parent class will not reschedule us
     mouseCriterion = mouseAndAnimationCriterion;
     // Change to a "move" cursor
     if (parentComponent != null) {
       savedCursor = parentComponent.getCursor();
       parentComponent.setCursor(Cursor
           .getPredefinedCursor(Cursor.HAND_CURSOR));
     }
     return;
   }
   if (mev.getID() == MouseEvent.MOUSE_RELEASED) {
     // Mouse button released: restore original wakeup
     // criterion which only includes mouse activity, not
     // elapsed time
     mouseCriterion = savedMouseCriterion;
     // Switch the cursor back
     if (parentComponent != null)
       parentComponent.setCursor(savedCursor);
     return;
   }
   previousX = x;
   previousY = y;
 }
 /**
  * Responds to a button2 event (press, release, or drag). On a press, the
  * method records the initial cursor location. On a drag, the difference
  * between the current and previous cursor location provides a delta that
  * controls the amount by which to rotate in X and Y.
  * 
  * @param mouseEvent
  *            the MouseEvent to respond to
  */
 public void onButton2(MouseEvent mev) {
   if (subjectTransformGroup == null)
     return;
   int x = mev.getX();
   int y = mev.getY();
   if (mev.getID() == MouseEvent.MOUSE_PRESSED) {
     // Mouse button pressed: record position
     previousX = x;
     previousY = y;
     initialX = x;
     initialY = y;
     // Change to a "rotate" cursor
     if (parentComponent != null) {
       savedCursor = parentComponent.getCursor();
       parentComponent.setCursor(Cursor
           .getPredefinedCursor(Cursor.MOVE_CURSOR));
     }
     return;
   }
   if (mev.getID() == MouseEvent.MOUSE_RELEASED) {
     // Mouse button released: do nothing
     // Switch the cursor back
     if (parentComponent != null)
       parentComponent.setCursor(savedCursor);
     return;
   }
   //
   // Mouse moved while button down: create a rotation
   //
   // Compute the delta in X and Y from the previous
   // position. Use the delta to compute rotation
   // angles with the mapping:
   //
   //   positive X mouse delta --> negative Y-axis rotation
   //   positive Y mouse delta --> negative X-axis rotation
   //
   // where positive X mouse movement is to the right, and
   // positive Y mouse movement is **down** the screen.
   //
   int deltaX = x - previousX;
   int deltaY = 0;
   if (Math.abs(y - initialY) > DELTAY_DEADZONE) {
     // Cursor has moved far enough vertically to consider
     // it intentional, so get it"s delta.
     deltaY = y - previousY;
   }
   if (deltaX > UNUSUAL_XDELTA || deltaX < -UNUSUAL_XDELTA
       || deltaY > UNUSUAL_YDELTA || deltaY < -UNUSUAL_YDELTA) {
     // Deltas are too huge to be believable. Probably a glitch.
     // Don"t record the new XY location, or do anything.
     return;
   }
   double xRotationAngle = -deltaY * XRotationFactor;
   double yRotationAngle = -deltaX * YRotationFactor;
   //
   // Build transforms
   //
   transform1.rotX(xRotationAngle);
   transform2.rotY(yRotationAngle);
   // Get and save the current transform matrix
   subjectTransformGroup.getTransform(currentTransform);
   currentTransform.get(matrix);
   translate.set(matrix.m03, matrix.m13, matrix.m23);
   // Translate to the origin, rotate, then translate back
   currentTransform.setTranslation(origin);
   currentTransform.mul(transform2, currentTransform);
   currentTransform.mul(transform1);
   currentTransform.setTranslation(translate);
   // Update the transform group
   subjectTransformGroup.setTransform(currentTransform);
   previousX = x;
   previousY = y;
 }
 /**
  * Responds to a button3 event (press, release, or drag). On a drag, the
  * difference between the current and previous cursor location provides a
  * delta that controls the amount by which to translate in X and Y.
  * 
  * @param mouseEvent
  *            the MouseEvent to respond to
  */
 public void onButton3(MouseEvent mev) {
   if (subjectTransformGroup == null)
     return;
   int x = mev.getX();
   int y = mev.getY();
   if (mev.getID() == MouseEvent.MOUSE_PRESSED) {
     // Mouse button pressed: record position
     previousX = x;
     previousY = y;
     // Change to a "move" cursor
     if (parentComponent != null) {
       savedCursor = parentComponent.getCursor();
       parentComponent.setCursor(Cursor
           .getPredefinedCursor(Cursor.MOVE_CURSOR));
     }
     return;
   }
   if (mev.getID() == MouseEvent.MOUSE_RELEASED) {
     // Mouse button released: do nothing
     // Switch the cursor back
     if (parentComponent != null)
       parentComponent.setCursor(savedCursor);
     return;
   }
   //
   // Mouse moved while button down: create a translation
   //
   // Compute the delta in X and Y from the previous
   // position. Use the delta to compute translation
   // distances with the mapping:
   //
   //   positive X mouse delta --> positive X-axis translation
   //   positive Y mouse delta --> negative Y-axis translation
   //
   // where positive X mouse movement is to the right, and
   // positive Y mouse movement is **down** the screen.
   //
   int deltaX = x - previousX;
   int deltaY = y - previousY;
   if (deltaX > UNUSUAL_XDELTA || deltaX < -UNUSUAL_XDELTA
       || deltaY > UNUSUAL_YDELTA || deltaY < -UNUSUAL_YDELTA) {
     // Deltas are too huge to be believable. Probably a glitch.
     // Don"t record the new XY location, or do anything.
     return;
   }
   double xTranslationDistance = deltaX * XTranslationFactor;
   double yTranslationDistance = -deltaY * YTranslationFactor;
   //
   // Build transforms
   //
   translate.set(xTranslationDistance, yTranslationDistance, 0.0);
   transform1.set(translate);
   // Get and save the current transform
   subjectTransformGroup.getTransform(currentTransform);
   // Translate as needed
   currentTransform.mul(transform1);
   // Update the transform group
   subjectTransformGroup.setTransform(currentTransform);
   previousX = x;
   previousY = y;
 }

} // //CLASS //CheckboxMenu - build a menu of grouped checkboxes // //DESCRIPTION //The class creates a menu with one or more CheckboxMenuItem"s //and monitors that menu. When a menu checkbox is picked, the //previous one is turned off (in radio-button style). Then, //a given listener"s checkboxChanged method is called, passing it //the menu and the item checked. // class CheckboxMenu extends Menu implements ItemListener {

 // State
 protected CheckboxMenuItem[] checks = null;
 protected int current = 0;
 protected CheckboxMenuListener listener = null;
 //  Construct
 public CheckboxMenu(String name, NameValue[] items,
     CheckboxMenuListener listen) {
   this(name, items, 0, listen);
 }
 public CheckboxMenu(String name, NameValue[] items, int cur,
     CheckboxMenuListener listen) {
   super(name);
   current = cur;
   listener = listen;
   if (items == null)
     return;
   checks = new CheckboxMenuItem[items.length];
   for (int i = 0; i < items.length; i++) {
     checks[i] = new CheckboxMenuItem(items[i].name, false);
     checks[i].addItemListener(this);
     add(checks[i]);
   }
   checks[cur].setState(true);
 }
 //  Handle checkbox changed events
 public void itemStateChanged(ItemEvent event) {
   Object src = event.getSource();
   for (int i = 0; i < checks.length; i++) {
     if (src == checks[i]) {
       // Update the checkboxes
       checks[current].setState(false);
       current = i;
       checks[current].setState(true);
       if (listener != null)
         listener.checkboxChanged(this, i);
       return;
     }
   }
 }
 // Methods to get and set state
 public int getCurrent() {
   return current;
 }
 public void setCurrent(int cur) {
   if (cur < 0 || cur >= checks.length)
     return; // ignore out of range choices
   if (checks == null)
     return;
   checks[current].setState(false);
   current = cur;
   checks[current].setState(true);
 }
 public CheckboxMenuItem getSelectedCheckbox() {
   if (checks == null)
     return null;
   return checks[current];
 }
 public void setSelectedCheckbox(CheckboxMenuItem item) {
   if (checks == null)
     return;
   for (int i = 0; i < checks.length; i++) {
     if (item == checks[i]) {
       checks[i].setState(false);
       current = i;
       checks[i].setState(true);
     }
   }
 }

} /**

* ViewerBehavior
* 
* @version 1.0, 98/04/16
*/

/**

* Wakeup on mouse button presses, releases, and mouse movements and generate
* transforms for a transform group. Classes that extend this class impose
* specific symantics, such as "Examine" or "Walk" viewing, similar to the
* navigation types used by VRML browsers.
* 
* To support systems with 2 or 1 mouse buttons, the following alternate
* mappings are supported while dragging with any mouse button held down and
* zero or more keyboard modifiers held down:
* 
* No modifiers = Button 1 ALT = Button 2 Meta = Button 3 Control = Button 3
* 
* The behavior automatically modifies a TransformGroup provided to the
* constructor. The TransformGroup"s transform can be set at any time by the
* application or other behaviors to cause the viewer"s rotation and translation
* to be reset.
*/

// This class is inspired by the MouseBehavior, MouseRotate, // MouseTranslate, and MouseZoom utility behaviors provided with // Java 3D. This class differs from those utilities in that it: // // (a) encapsulates all three behaviors into one in order to // enforce a specific viewing symantic // // (b) supports set/get of the rotation and translation factors // that control the speed of movement. // // (c) supports the "Control" modifier as an alternative to the // "Meta" modifier not present on PC, Mac, and most non-Sun // keyboards. This makes button3 behavior usable on PCs, // Macs, and other systems with fewer than 3 mouse buttons. abstract class ViewerBehavior extends Behavior {

 // Keep track of the transform group who"s transform we modify
 // during mouse motion.
 protected TransformGroup subjectTransformGroup = null;
 // Keep a set of wakeup criterion for different mouse-generated
 // event types.
 protected WakeupCriterion[] mouseEvents = null;
 protected WakeupOr mouseCriterion = null;
 // Track which button was last pressed
 protected static final int BUTTONNONE = -1;
 protected static final int BUTTON1 = 0;
 protected static final int BUTTON2 = 1;
 protected static final int BUTTON3 = 2;
 protected int buttonPressed = BUTTONNONE;
 // Keep a few Transform3Ds for use during event processing. This
 // avoids having to allocate new ones on each event.
 protected Transform3D currentTransform = new Transform3D();
 protected Transform3D transform1 = new Transform3D();
 protected Transform3D transform2 = new Transform3D();
 protected Matrix4d matrix = new Matrix4d();
 protected Vector3d origin = new Vector3d(0.0, 0.0, 0.0);
 protected Vector3d translate = new Vector3d(0.0, 0.0, 0.0);
 // Unusual X and Y delta limits.
 protected static final int UNUSUAL_XDELTA = 400;
 protected static final int UNUSUAL_YDELTA = 400;
 protected Component parentComponent = null;
 /**
  * Construct a viewer behavior that listens to mouse movement and button
  * presses to generate rotation and translation transforms written into a
  * transform group given later with the setTransformGroup( ) method.
  */
 public ViewerBehavior() {
   super();
 }
 /**
  * Construct a viewer behavior that listens to mouse movement and button
  * presses to generate rotation and translation transforms written into a
  * transform group given later with the setTransformGroup( ) method.
  * 
  * @param parent
  *            The AWT Component that contains the area generating mouse
  *            events.
  */
 public ViewerBehavior(Component parent) {
   super();
   parentComponent = parent;
 }
 /**
  * Construct a viewer behavior that listens to mouse movement and button
  * presses to generate rotation and translation transforms written into the
  * given transform group.
  * 
  * @param transformGroup
  *            The transform group to be modified by the behavior.
  */
 public ViewerBehavior(TransformGroup transformGroup) {
   super();
   subjectTransformGroup = transformGroup;
 }
 /**
  * Construct a viewer behavior that listens to mouse movement and button
  * presses to generate rotation and translation transforms written into the
  * given transform group.
  * 
  * @param transformGroup
  *            The transform group to be modified by the behavior.
  * @param parent
  *            The AWT Component that contains the area generating mouse
  *            events.
  */
 public ViewerBehavior(TransformGroup transformGroup, Component parent) {
   super();
   subjectTransformGroup = transformGroup;
   parentComponent = parent;
 }
 /**
  * Set the transform group modified by the viewer behavior. Setting the
  * transform group to null disables the behavior until the transform group
  * is again set to an existing group.
  * 
  * @param transformGroup
  *            The new transform group to be modified by the behavior.
  */
 public void setTransformGroup(TransformGroup transformGroup) {
   subjectTransformGroup = transformGroup;
 }
 /**
  * Get the transform group modified by the viewer behavior.
  */
 public TransformGroup getTransformGroup() {
   return subjectTransformGroup;
 }
 /**
  * Sets the parent component who"s cursor will be changed during mouse
  * drags. If no component is given is given to the constructor, or set via
  * this method, no cursor changes will be done.
  * 
  * @param parent
  *            the AWT Component, such as a Frame, within which cursor
  *            changes should take place during mouse drags
  */
 public void setParentComponent(Component parent) {
   parentComponent = parent;
 }
 /*
  * Gets the parent frame within which the cursor changes during mouse drags.
  * 
  * @return the AWT Component, such as a Frame, within which cursor changes
  * should take place during mouse drags. Returns null if no parent is set.
  */
 public Component getParentComponent() {
   return parentComponent;
 }
 /**
  * Initialize the behavior.
  */
 public void initialize() {
   // Wakeup when the mouse is dragged or when a mouse button
   // is pressed or released.
   mouseEvents = new WakeupCriterion[3];
   mouseEvents[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED);
   mouseEvents[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED);
   mouseEvents[2] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED);
   mouseCriterion = new WakeupOr(mouseEvents);
   wakeupOn(mouseCriterion);
 }
 /**
  * Process a new wakeup. Interpret mouse button presses, releases, and mouse
  * drags.
  * 
  * @param criteria
  *            The wakeup criteria causing the behavior wakeup.
  */
 public void processStimulus(Enumeration criteria) {
   WakeupCriterion wakeup = null;
   AWTEvent[] event = null;
   int whichButton = BUTTONNONE;
   // Process all pending wakeups
   while (criteria.hasMoreElements()) {
     wakeup = (WakeupCriterion) criteria.nextElement();
     if (wakeup instanceof WakeupOnAWTEvent) {
       event = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
       // Process all pending events
       for (int i = 0; i < event.length; i++) {
         if (event[i].getID() != MouseEvent.MOUSE_PRESSED
             && event[i].getID() != MouseEvent.MOUSE_RELEASED
             && event[i].getID() != MouseEvent.MOUSE_DRAGGED)
           // Ignore uninteresting mouse events
           continue;
         //
         // Regretably, Java event handling (or perhaps
         // underlying OS event handling) doesn"t always
         // catch button bounces (redundant presses and
         // releases), or order events so that the last
         // drag event is delivered before a release.
         // This means we can get stray events that we
         // filter out here.
         //
         if (event[i].getID() == MouseEvent.MOUSE_PRESSED
             && buttonPressed != BUTTONNONE)
           // Ignore additional button presses until a release
           continue;
         if (event[i].getID() == MouseEvent.MOUSE_RELEASED
             && buttonPressed == BUTTONNONE)
           // Ignore additional button releases until a press
           continue;
         if (event[i].getID() == MouseEvent.MOUSE_DRAGGED
             && buttonPressed == BUTTONNONE)
           // Ignore drags until a press
           continue;
         MouseEvent mev = (MouseEvent) event[i];
         int modifiers = mev.getModifiers();
         //
         // Unfortunately, the underlying event handling
         // doesn"t do a "grab" operation when a mouse button
         // is pressed. This means that once a button is
         // pressed, if another mouse button or a keyboard
         // modifier key is pressed, the delivered mouse event
         // will show that a different button is being held
         // down. For instance:
         //
         // Action Event
         //  Button 1 press Button 1 press
         //  Drag with button 1 down Button 1 drag
         //  ALT press -
         //  Drag with ALT & button 1 down Button 2 drag
         //  Button 1 release Button 2 release
         //
         // The upshot is that we can get a button press
         // without a matching release, and the button
         // associated with a drag can change mid-drag.
         //
         // To fix this, we watch for an initial button
         // press, and thenceforth consider that button
         // to be the one held down, even if additional
         // buttons get pressed, and despite what is
         // reported in the event. Only when a button is
         // released, do we end such a grab.
         //
         if (buttonPressed == BUTTONNONE) {
           // No button is pressed yet, figure out which
           // button is down now and how to direct events
           if (((modifiers & InputEvent.BUTTON3_MASK) != 0)
               || (((modifiers & InputEvent.BUTTON1_MASK) != 0) && ((modifiers & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK))) {
             // Button 3 activity (META or CTRL down)
             whichButton = BUTTON3;
           } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
             // Button 2 activity (ALT down)
             whichButton = BUTTON2;
           } else {
             // Button 1 activity (no modifiers down)
             whichButton = BUTTON1;
           }
           // If the event is to press a button, then
           // record that that button is now down
           if (event[i].getID() == MouseEvent.MOUSE_PRESSED)
             buttonPressed = whichButton;
         } else {
           // Otherwise a button was pressed earlier and
           // hasn"t been released yet. Assign all further
           // events to it, even if ALT, META, CTRL, or
           // another button has been pressed as well.
           whichButton = buttonPressed;
         }
         // Distribute the event
         switch (whichButton) {
         case BUTTON1:
           onButton1(mev);
           break;
         case BUTTON2:
           onButton2(mev);
           break;
         case BUTTON3:
           onButton3(mev);
           break;
         default:
           break;
         }
         // If the event is to release a button, then
         // record that that button is now up
         if (event[i].getID() == MouseEvent.MOUSE_RELEASED)
           buttonPressed = BUTTONNONE;
       }
       continue;
     }
     if (wakeup instanceof WakeupOnElapsedFrames) {
       onElapsedFrames((WakeupOnElapsedFrames) wakeup);
       continue;
     }
   }
   // Reschedule us for another wakeup
   wakeupOn(mouseCriterion);
 }
 /**
  * Default X and Y rotation factors, and XYZ translation factors.
  */
 public static final double DEFAULT_XROTATION_FACTOR = 0.02;
 public static final double DEFAULT_YROTATION_FACTOR = 0.005;
 public static final double DEFAULT_XTRANSLATION_FACTOR = 0.02;
 public static final double DEFAULT_YTRANSLATION_FACTOR = 0.02;
 public static final double DEFAULT_ZTRANSLATION_FACTOR = 0.04;
 protected double XRotationFactor = DEFAULT_XROTATION_FACTOR;
 protected double YRotationFactor = DEFAULT_YROTATION_FACTOR;
 protected double XTranslationFactor = DEFAULT_XTRANSLATION_FACTOR;
 protected double YTranslationFactor = DEFAULT_YTRANSLATION_FACTOR;
 protected double ZTranslationFactor = DEFAULT_ZTRANSLATION_FACTOR;
 /**
  * Set the X rotation scaling factor for X-axis rotations.
  * 
  * @param factor
  *            The new scaling factor.
  */
 public void setXRotationFactor(double factor) {
   XRotationFactor = factor;
 }
 /**
  * Get the current X rotation scaling factor for X-axis rotations.
  */
 public double getXRotationFactor() {
   return XRotationFactor;
 }
 /**
  * Set the Y rotation scaling factor for Y-axis rotations.
  * 
  * @param factor
  *            The new scaling factor.
  */
 public void setYRotationFactor(double factor) {
   YRotationFactor = factor;
 }
 /**
  * Get the current Y rotation scaling factor for Y-axis rotations.
  */
 public double getYRotationFactor() {
   return YRotationFactor;
 }
 /**
  * Set the X translation scaling factor for X-axis translations.
  * 
  * @param factor
  *            The new scaling factor.
  */
 public void setXTranslationFactor(double factor) {
   XTranslationFactor = factor;
 }
 /**
  * Get the current X translation scaling factor for X-axis translations.
  */
 public double getXTranslationFactor() {
   return XTranslationFactor;
 }
 /**
  * Set the Y translation scaling factor for Y-axis translations.
  * 
  * @param factor
  *            The new scaling factor.
  */
 public void setYTranslationFactor(double factor) {
   YTranslationFactor = factor;
 }
 /**
  * Get the current Y translation scaling factor for Y-axis translations.
  */
 public double getYTranslationFactor() {
   return YTranslationFactor;
 }
 /**
  * Set the Z translation scaling factor for Z-axis translations.
  * 
  * @param factor
  *            The new scaling factor.
  */
 public void setZTranslationFactor(double factor) {
   ZTranslationFactor = factor;
 }
 /**
  * Get the current Z translation scaling factor for Z-axis translations.
  */
 public double getZTranslationFactor() {
   return ZTranslationFactor;
 }
 /**
  * Respond to a button1 event (press, release, or drag).
  * 
  * @param mouseEvent
  *            A MouseEvent to respond to.
  */
 public abstract void onButton1(MouseEvent mouseEvent);
 /**
  * Respond to a button2 event (press, release, or drag).
  * 
  * @param mouseEvent
  *            A MouseEvent to respond to.
  */
 public abstract void onButton2(MouseEvent mouseEvent);
 /**
  * Responed to a button3 event (press, release, or drag).
  * 
  * @param mouseEvent
  *            A MouseEvent to respond to.
  */
 public abstract void onButton3(MouseEvent mouseEvent);
 /**
  * Respond to an elapsed frames event (assuming subclass has set up a wakeup
  * criterion for it).
  * 
  * @param time
  *            A WakeupOnElapsedFrames criterion to respond to.
  */
 public abstract void onElapsedFrames(WakeupOnElapsedFrames timeEvent);

} // //CLASS //NameValue - create a handy name-value pair // //DESCRIPTION //It is frequently handy to have one or more name-value pairs //with which to store named colors, named positions, named textures, //and so forth. Several of the examples use this class. // //AUTHOR //David R. Nadeau / San Diego Supercomputer Center // class NameValue {

 public String name;
 public Object value;
 public NameValue(String n, Object v) {
   name = n;
   value = v;
 }

}


      </source>
   
  
 
  



Hello Universe 1

   <source lang="java">

/*

* @(#)HelloUniverse1.java 1.55 02/10/21 13:43:36
* 
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*  - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* 
* 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.
* 
* You acknowledge that Software is not designed,licensed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.GraphicsConfiguration; import javax.media.j3d.Alpha; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.vecmath.Point3d; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.universe.SimpleUniverse; public class HelloUniverse1 extends Applet {

 private SimpleUniverse u = null;
 public BranchGroup createSceneGraph() {
   // Create the root of the branch graph
   BranchGroup objRoot = new BranchGroup();
   // Create the TransformGroup node and initialize it to the
   // identity. Enable the TRANSFORM_WRITE capability so that
   // our behavior code can modify it at run time. Add it to
   // the root of the subgraph.
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objRoot.addChild(objTrans);
   // Create a simple Shape3D node; add it to the scene graph.
   objTrans.addChild(new ColorCube(0.4));
   // Create a new Behavior object that will perform the
   // desired operation on the specified transform and add
   // it into the scene graph.
   Transform3D yAxis = new Transform3D();
   Alpha rotationAlpha = new Alpha(-1, 4000);
   RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,
       objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   rotator.setSchedulingBounds(bounds);
   objRoot.addChild(rotator);
   // Have Java 3D perform optimizations on this scene graph.
   objRoot.rupile();
   return objRoot;
 }
 public HelloUniverse1() {
 }
 public void init() {
   setLayout(new BorderLayout());
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   Canvas3D c = new Canvas3D(config);
   add("Center", c);
   // Create a simple scene and attach it to the virtual universe
   BranchGroup scene = createSceneGraph();
   u = new SimpleUniverse(c);
   // This will move the ViewPlatform back a bit so the
   // objects in the scene can be viewed.
   u.getViewingPlatform().setNominalViewingTransform();
   u.addBranchGraph(scene);
 }
 public void destroy() {
   u.cleanup();
 }
 //
 // The following allows HelloUniverse to be run as an application
 // as well as an applet
 //
 public static void main(String[] args) {
   new MainFrame(new HelloUniverse1(), 256, 256);
 }

}


      </source>
   
  
 
  



Illustrate some of the features of the SimpleUniverse class

   <source lang="java">

/**********************************************************

Copyright (C) 2001   Daniel Selman
First distributed with the book "Java 3D Programming"
by Daniel Selman and published by Manning Publications.
http://manning.ru/selman
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
The license can be found on the WWW at:
http://www.fsf.org/copyleft/gpl.html
Or by writing to:
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
Authors can be contacted at:
Daniel Selman: daniel@selman.org
If you make changes you think others would like, please 
contact one of the authors or someone at the 
www.j3d.org web site.
**************************************************************/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Graphics; import java.awt.GraphicsConfigTemplate; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.net.URL; import java.util.Hashtable; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.AudioDevice; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.Bounds; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.media.j3d.Group; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.View; import javax.media.j3d.ViewPlatform; import javax.media.j3d.VirtualUniverse; import javax.vecmath.Color3f; import javax.vecmath.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.geometry.GeometryInfo; import com.sun.j3d.utils.geometry.NormalGenerator; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.MultiTransformGroup; import com.sun.j3d.utils.universe.PlatformGeometry; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.Viewer; import com.sun.j3d.utils.universe.ViewerAvatar; import com.sun.j3d.utils.universe.ViewingPlatform; /**

* This example illustrates some of the features of the SimpleUniverse class. It
* creates 3 views into a scengraph and associates a ViewerAvatar and
* PlatformGeometry with each Viewer object.
* <p>
* The example creates a very simple navigation environment where each Viewer of
* the environment can navigate using the keyboard and see the other viewer.
*/

public class PlatformTest extends Applet implements ActionListener {

 // size of each Canvas3D
 static final int m_kWidth = 256;
 static final int m_kHeight = 256;
 // table used to map the name of a Viewer to its KeyNavigatorBehavior
 Hashtable m_KeyHashtable = null;
 BoundingSphere m_Bounds = null;
 public PlatformTest() {
   m_KeyHashtable = new Hashtable();
   m_Bounds = new BoundingSphere(new Point3d(0, 0, 0), 100);
   // get the graphics configuration for the graphics device
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   // create the first canvas, this is the top-down view
   Canvas3D c = new Canvas3D(config);
   c.setSize(m_kWidth, m_kHeight);
   add(c);
   // create the second canvas, this is used for "Jim"s" Viewer
   Canvas3D c2 = new Canvas3D(config);
   c2.setSize(m_kWidth, m_kHeight);
   add(c2);
   // create the third canvas, this is used for "Dan"s" Viewer
   Canvas3D c3 = new Canvas3D(config);
   c3.setSize(m_kWidth, m_kHeight);
   add(c3);
   // Create the simple environment
   BranchGroup scene = createSceneGraph();
   // create the first Viewer, this is a static top-down view
   // create a ViewingPlatform with 2 TransformGroups above the
   // ViewPlatform
   ViewingPlatform vp = new ViewingPlatform(2);
   // create the Viewer and attach to the first canvas
   Viewer viewer = new Viewer(c);
   // rotate and position the first Viewer above the environment
   Transform3D t3d = new Transform3D();
   t3d.rotX(Math.PI / 2.0);
   t3d.setTranslation(new Vector3d(0, 0, -40));
   t3d.invert();
   MultiTransformGroup mtg = vp.getMultiTransformGroup();
   mtg.getTransformGroup(0).setTransform(t3d);
   // create a SimpleUniverse from the ViewingPlatform and Viewer
   SimpleUniverse u = new SimpleUniverse(vp, viewer);
   // add the geometry to the scenegraph
   u.addBranchGraph(scene);
   // add two more Viewers to the scenegraph
   u.getLocale().addBranchGraph(
       createViewer(c2, "Jim", new Color3f(0.1f, 1.0f, 1.0f), -5, 8));
   u.getLocale().addBranchGraph(
       createViewer(c3, "Dan", new Color3f(1.0f, 0.1f, 0.1f), 2, -8));
 }
 ViewingPlatform createViewer(Canvas3D c, String szName, Color3f objColor,
     double x, double z) {
   // create a Viewer and attach to its canvas
   // a Canvas3D can only be attached to a single Viewer
   Viewer viewer2 = new Viewer(c);
   // create a ViewingPlatform with 1 TransformGroups above the
   // ViewPlatform
   ViewingPlatform vp2 = new ViewingPlatform(1);
   // create and assign the PlatformGeometry to the Viewer
   vp2.setPlatformGeometry(createPlatformGeometry(szName));
   // create and assign the ViewerAvatar to the Viewer
   viewer2.setAvatar(createViewerAvatar(szName, objColor));
   // set the initial position for the Viewer
   Transform3D t3d = new Transform3D();
   t3d.setTranslation(new Vector3d(x, 0, z));
   vp2.getViewPlatformTransform().setTransform(t3d);
   // set capabilities on the TransformGroup so that the
   // KeyNavigatorBehavior
   // can modify the Viewer"s position
   vp2.getViewPlatformTransform().setCapability(
       TransformGroup.ALLOW_TRANSFORM_WRITE);
   vp2.getViewPlatformTransform().setCapability(
       TransformGroup.ALLOW_TRANSFORM_READ);
   // attach a navigation behavior to the position of the viewer
   KeyNavigatorBehavior key = new KeyNavigatorBehavior(vp2
       .getViewPlatformTransform());
   key.setSchedulingBounds(m_Bounds);
   key.setEnable(false);
   // add the KeyNavigatorBehavior to the ViewingPlatform
   vp2.addChild(key);
   // set the ViewingPlatform for the Viewer
   viewer2.setViewingPlatform(vp2);
   // associate the name of the Viewer with its KeyNavigatorBehavior
   m_KeyHashtable.put(szName, key);
   // create a button to switch the Viewer ON.
   Button button = new Button(szName);
   button.addActionListener(this);
   add(button);
   return vp2;
 }
 // create a tiled environment from -12 to +12. The environment
 // is created from a QuadArray. The environment is surrounded by a ColorCube
 // "wall" that is 2 units high (from Z = -1 to Z = 1).
 public BranchGroup createSceneGraph() {
   final int LAND_WIDTH = 12;
   final float LAND_HEIGHT = -1.0f;
   final int LAND_LENGTH = 12;
   final int nTileSize = 2;
   // calculate how many vertices we need to store all the "tiles"
   // that compose the QuadArray.
   final int nNumTiles = ((LAND_LENGTH / nTileSize) * 2)
       * ((LAND_WIDTH / nTileSize) * 2);
   final int nVertexCount = 4 * nNumTiles;
   Point3f[] coordArray = new Point3f[nVertexCount];
   Point2f[] texCoordArray = new Point2f[nVertexCount];
   // create an Appearance and load a texture
   Appearance app = new Appearance();
   Texture tex = new TextureLoader("land.jpg", this).getTexture();
   app.setTexture(tex);
   // create the parent BranchGroup
   BranchGroup bg = new BranchGroup();
   int nItem = 0;
   // loop over all the tiles in the environment
   for (int x = -LAND_WIDTH; x <= LAND_WIDTH; x += nTileSize) {
     for (int z = -LAND_LENGTH; z <= LAND_LENGTH; z += nTileSize) {
       // if we are on the border of the environment create a
       // TransformGroup to position a ColorCube to create a "wall"
       if (x == -LAND_WIDTH || x == LAND_WIDTH || z == -LAND_LENGTH
           || z == LAND_LENGTH) {
         TransformGroup tg = new TransformGroup();
         Transform3D t3d = new Transform3D();
         t3d.setTranslation(new Vector3d(x, 0, z));
         tg.setTransform(t3d);
         tg.addChild(new ColorCube(nTileSize / 2));
         bg.addChild(tg);
       }
       // if we are not on the last row or column create a "tile"
       // and add to the QuadArray. Use CCW winding and assign texture
       // coordinates.
       if (z < LAND_LENGTH && x < LAND_WIDTH) {
         coordArray[nItem] = new Point3f(x, LAND_HEIGHT, z);
         texCoordArray[nItem++] = new Point2f(0, 0);
         coordArray[nItem] = new Point3f(x, LAND_HEIGHT, z
             + nTileSize);
         texCoordArray[nItem++] = new Point2f(1, 0);
         coordArray[nItem] = new Point3f(x + nTileSize, LAND_HEIGHT,
             z + nTileSize);
         texCoordArray[nItem++] = new Point2f(1, 1);
         coordArray[nItem] = new Point3f(x + nTileSize, LAND_HEIGHT,
             z);
         texCoordArray[nItem++] = new Point2f(0, 1);
       }
     }
   }
   // create a GeometryInfo and generate Normal vectors
   // for the QuadArray that was populated.
   GeometryInfo gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
   gi.setCoordinates(coordArray);
   gi.setTextureCoordinates(texCoordArray);
   NormalGenerator normalGenerator = new NormalGenerator();
   normalGenerator.generateNormals(gi);
   // wrap the GeometryArray in a Shape3D
   Shape3D shape = new Shape3D(gi.getGeometryArray(), app);
   // add the Shape3D to the parent BranchGroup
   bg.addChild(shape);
   // create some lights for the scene
   Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
   Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
   Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);
   AmbientLight aLgt = new AmbientLight(alColor);
   aLgt.setInfluencingBounds(m_Bounds);
   DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
   lgt1.setInfluencingBounds(m_Bounds);
   // add the lights to the parent BranchGroup
   bg.addChild(aLgt);
   bg.addChild(lgt1);
   // create a light gray background
   Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
   back.setApplicationBounds(m_Bounds);
   bg.addChild(back);
   // compile the whole scene
   //bg.rupile();
   return bg;
 }
 // creates and positions a simple Cone to represent the Viewer.
 // The Cone is aligned and scaled such that it is similar to a
 // 3D "turtle".... Aaah good old Logo.
 ViewerAvatar createViewerAvatar(String szText, Color3f objColor) {
   ViewerAvatar viewerAvatar = new ViewerAvatar();
   // rotate the Cone so that it is lying down and
   // points sharp-end towards the Viewer"s field of view.
   TransformGroup tg = new TransformGroup();
   Transform3D t3d = new Transform3D();
   t3d.setEuler(new Vector3d(Math.PI / 2.0, Math.PI, 0));
   tg.setTransform(t3d);
   // create appearance and material for the Cone
   Appearance app = new Appearance();
   Color3f black = new Color3f(0.4f, 0.2f, 0.1f);
   app.setMaterial(new Material(objColor, black, objColor, black, 90.0f));
   // create the Primitive and add to the parent BranchGroup
   tg.addChild(new Cone(1, 3, Primitive.GENERATE_NORMALS, app));
   viewerAvatar.addChild(tg);
   return viewerAvatar;
 }
 // create a simple Raster text label used to help
 // identify the viewer.
 PlatformGeometry createPlatformGeometry(String szText) {
   PlatformGeometry pg = new PlatformGeometry();
   pg.addChild(createLabel(szText, 0f, 2f, 0f));
   return pg;
 }
 // creates a simple Raster text label (similar to Text2D)
 private Shape3D createLabel(String szText, float x, float y, float z) {
   BufferedImage bufferedImage = new BufferedImage(25, 14,
       BufferedImage.TYPE_INT_RGB);
   Graphics g = bufferedImage.getGraphics();
   g.setColor(Color.white);
   g.drawString(szText, 2, 12);
   ImageComponent2D imageComponent2D = new ImageComponent2D(
       ImageComponent2D.FORMAT_RGB, bufferedImage);
   // create the Raster for the image
   javax.media.j3d.Raster renderRaster = new javax.media.j3d.Raster(
       new Point3f(x, y, z), javax.media.j3d.Raster.RASTER_COLOR, 0,
       0, bufferedImage.getWidth(), bufferedImage.getHeight(),
       imageComponent2D, null);
   return new Shape3D(renderRaster);
 }
 // Enables the KeyNavigatorBehavior associated with the
 // AWT button that was pressed for the Viewer. Disables all other
 // KeyNavigatorBehaviors for non-active Viewers.
 public void actionPerformed(ActionEvent event) {
   KeyNavigatorBehavior key = (KeyNavigatorBehavior) m_KeyHashtable
       .get(event.getActionCommand());
   Object[] keysArray = m_KeyHashtable.values().toArray();
   for (int n = 0; n < keysArray.length; n++) {
     KeyNavigatorBehavior keyAtIndex = (KeyNavigatorBehavior) keysArray[n];
     keyAtIndex.setEnable(keyAtIndex == key);
     if (keyAtIndex == key)
       System.out.println("Enabled: " + event.getActionCommand());
   }
 }
 public static void main(String[] args) {
   new MainFrame(new PlatformTest(), (int) (m_kWidth * 3.5),
       (int) (m_kHeight * 1.1));
 }

} /*******************************************************************************

* Copyright (C) 2001 Daniel Selman
* 
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.ru/selman
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
* 
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
* 
* Authors can be contacted at: Daniel Selman: daniel@selman.org
* 
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/

//***************************************************************************** /**

* Java3dApplet
* 
* Base class for defining a Java 3D applet. Contains some useful methods for
* defining views and scenegraphs etc.
* 
* @author Daniel Selman
* @version 1.0
*/

//***************************************************************************** abstract class Java3dApplet extends Applet {

 public static int m_kWidth = 300;
 public static int m_kHeight = 300;
 protected String[] m_szCommandLineArray = null;
 protected VirtualUniverse m_Universe = null;
 protected BranchGroup m_SceneBranchGroup = null;
 protected Bounds m_ApplicationBounds = null;
 //  protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;
 public Java3dApplet() {
 }
 public boolean isApplet() {
   try {
     System.getProperty("user.dir");
     System.out.println("Running as Application.");
     return false;
   } catch (Exception e) {
   }
   System.out.println("Running as Applet.");
   return true;
 }
 public URL getWorkingDirectory() throws java.net.MalformedURLException {
   URL url = null;
   try {
     File file = new File(System.getProperty("user.dir"));
     System.out.println("Running as Application:");
     System.out.println("   " + file.toURL());
     return file.toURL();
   } catch (Exception e) {
   }
   System.out.println("Running as Applet:");
   System.out.println("   " + getCodeBase());
   return getCodeBase();
 }
 public VirtualUniverse getVirtualUniverse() {
   return m_Universe;
 }
 //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
 //return m_Java3dTree;
 //  }
 public Locale getFirstLocale() {
   java.util.Enumeration e = m_Universe.getAllLocales();
   if (e.hasMoreElements() != false)
     return (Locale) e.nextElement();
   return null;
 }
 protected Bounds getApplicationBounds() {
   if (m_ApplicationBounds == null)
     m_ApplicationBounds = createApplicationBounds();
   return m_ApplicationBounds;
 }
 protected Bounds createApplicationBounds() {
   m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   return m_ApplicationBounds;
 }
 protected Background createBackground() {
   Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
   back.setApplicationBounds(createApplicationBounds());
   return back;
 }
 public void initJava3d() {
   //  m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
   m_Universe = createVirtualUniverse();
   Locale locale = createLocale(m_Universe);
   BranchGroup sceneBranchGroup = createSceneBranchGroup();
   ViewPlatform vp = createViewPlatform();
   BranchGroup viewBranchGroup = createViewBranchGroup(
       getViewTransformGroupArray(), vp);
   createView(vp);
   Background background = createBackground();
   if (background != null)
     sceneBranchGroup.addChild(background);
   //    m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
   //  m_Java3dTree.recursiveApplyCapability(viewBranchGroup);
   locale.addBranchGraph(sceneBranchGroup);
   addViewBranchGroup(locale, viewBranchGroup);
   onDoneInit();
 }
 protected void onDoneInit() {
   //  m_Java3dTree.updateNodes(m_Universe);
 }
 protected double getScale() {
   return 1.0;
 }
 public TransformGroup[] getViewTransformGroupArray() {
   TransformGroup[] tgArray = new TransformGroup[1];
   tgArray[0] = new TransformGroup();
   // move the camera BACK a little...
   // note that we have to invert the matrix as
   // we are moving the viewer
   Transform3D t3d = new Transform3D();
   t3d.setScale(getScale());
   t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
   t3d.invert();
   tgArray[0].setTransform(t3d);
   return tgArray;
 }
 protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
   locale.addBranchGraph(bg);
 }
 protected Locale createLocale(VirtualUniverse u) {
   return new Locale(u);
 }
 protected BranchGroup createSceneBranchGroup() {
   m_SceneBranchGroup = new BranchGroup();
   return m_SceneBranchGroup;
 }
 protected View createView(ViewPlatform vp) {
   View view = new View();
   PhysicalBody pb = createPhysicalBody();
   PhysicalEnvironment pe = createPhysicalEnvironment();
   AudioDevice audioDevice = createAudioDevice(pe);
   if (audioDevice != null) {
     pe.setAudioDevice(audioDevice);
     audioDevice.initialize();
   }
   view.setPhysicalEnvironment(pe);
   view.setPhysicalBody(pb);
   if (vp != null)
     view.attachViewPlatform(vp);
   view.setBackClipDistance(getBackClipDistance());
   view.setFrontClipDistance(getFrontClipDistance());
   Canvas3D c3d = createCanvas3D();
   view.addCanvas3D(c3d);
   addCanvas3D(c3d);
   return view;
 }
 protected PhysicalBody createPhysicalBody() {
   return new PhysicalBody();
 }
 protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
   JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);
   if (javaSoundMixer == null)
     System.out.println("create of audiodevice failed");
   return javaSoundMixer;
 }
 protected PhysicalEnvironment createPhysicalEnvironment() {
   return new PhysicalEnvironment();
 }
 protected float getViewPlatformActivationRadius() {
   return 100;
 }
 protected ViewPlatform createViewPlatform() {
   ViewPlatform vp = new ViewPlatform();
   vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
   vp.setActivationRadius(getViewPlatformActivationRadius());
   return vp;
 }
 protected Canvas3D createCanvas3D() {
   GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
   gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
   GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
       .getScreenDevices();
   Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
   c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
   return c3d;
 }
 protected int getCanvas3dWidth(Canvas3D c3d) {
   return m_kWidth;
 }
 protected int getCanvas3dHeight(Canvas3D c3d) {
   return m_kHeight;
 }
 protected double getBackClipDistance() {
   return 100.0;
 }
 protected double getFrontClipDistance() {
   return 1.0;
 }
 protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray,
     ViewPlatform vp) {
   BranchGroup vpBranchGroup = new BranchGroup();
   if (tgArray != null && tgArray.length > 0) {
     Group parentGroup = vpBranchGroup;
     TransformGroup curTg = null;
     for (int n = 0; n < tgArray.length; n++) {
       curTg = tgArray[n];
       parentGroup.addChild(curTg);
       parentGroup = curTg;
     }
     tgArray[tgArray.length - 1].addChild(vp);
   } else
     vpBranchGroup.addChild(vp);
   return vpBranchGroup;
 }
 protected void addCanvas3D(Canvas3D c3d) {
   setLayout(new BorderLayout());
   add(c3d, BorderLayout.CENTER);
   doLayout();
 }
 protected VirtualUniverse createVirtualUniverse() {
   return new VirtualUniverse();
 }
 protected void saveCommandLineArguments(String[] szArgs) {
   m_szCommandLineArray = szArgs;
 }
 protected String[] getCommandLineArguments() {
   return m_szCommandLineArray;
 }

}

      </source>
   
  
 
  



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

   <source lang="java">

/* 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.rupile();
   // 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.rupile();
   // 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.rupile();
   // 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.rupile();
   // 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.ruponent 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.ruponent 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.ruponent 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.rupareTo("points") == 0) {
     polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_POINT);
   }
   /* Lines*/
   else if (renderingType.rupareTo("lines") == 0) {
     polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
   }
   /* Polygons */
   else if (renderingType.rupareTo("polygons") == 0) {
     /* is the default value*/
     polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); 
     coloringAttributes.setShadeModel(ColoringAttributes.SHADE_FLAT);
   }
   /* Gouraud */
   else if (renderingType.rupareTo("gouraud") == 0) {
     polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); /* is the default value*/
     coloringAttributes.setShadeModel(ColoringAttributes.SHADE_GOURAUD); /* is the default value*/
   }
   else if (renderingType.rupareTo("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 };

}


      </source>
   
  
 
  



MainFrame and SimpleUniverse

   <source lang="java">

/*******************************************************************************

* Copyright (C) 2001 Daniel Selman
* 
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.ru/selman
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
* 
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
* 
* Authors can be contacted at: Daniel Selman: daniel@selman.org
* 
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/

import java.applet.Applet; import javax.media.j3d.Alpha; import javax.media.j3d.Appearance; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.DirectionalLight; import javax.media.j3d.Material; import javax.media.j3d.PositionInterpolator; import javax.media.j3d.Texture; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Vector3f; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; /*

* This example builds a simple Java 3D Application using the SUN utility
* classes: MainFrame and SimpleUniverse. The example displays a moving sphere,
* in front of a background image. It uses a texture image and one light to
* increase the visual impact of the scene.
*/

public class SimpleTest extends Applet {

 /*
  * Create a simple Java 3D environment containing: a sphere (geometry), a
  * light,background geometry with an applied texture, and a behavior that
  * will move the sphere along the X-axis.
  */
 public SimpleTest() {
   // create the SimpleUniverse class that will
   // encapsulate the scene that we are building.
   // SimpleUniverse is a helper class (utility)
   // from SUN that is included with the core Java 3D
   // distribution.
   SimpleUniverse u = new SimpleUniverse();
   // create a BranchGroup. A BranchGroup is a node in
   // a Tree data structure that can have child nodes
   BranchGroup bgRoot = new BranchGroup();
   // create the Background node and add it to the SimpleUniverse
   u.addBranchGraph(createBackground());
   // create the behaviors to move the geometry along the X-axis.
   // The behavior is added as a child of the bgRoot node.
   // Anything add as a child of the tg node will be effected by the
   // behvior (will be moved along the X-axis).
   TransformGroup tg = createBehaviors(bgRoot);
   // add the Sphere geometry as a child of the tg
   // so that it will be moved along the X-axis.
   tg.addChild(createSceneGraph());
   // because the sphere was added at the 0,0,0 coordinate
   // and by default the viewer is also located at 0,0,0
   // we have to move the viewer back a little so that
   // she can see the scene.
   u.getViewingPlatform().setNominalViewingTransform();
   // add a light to the root BranchGroup to illuminate the scene
   addLights(bgRoot);
   // finally wire everything together by adding the root
   // BranchGroup to the SimpleUniverse
   u.addBranchGraph(bgRoot);
 }
 /*
  * Create the geometry for the scene. In this case we simply create a Sphere
  * (a built-in Java 3D primitive).
  */
 public BranchGroup createSceneGraph() {
   // create a parent BranchGroup node for the Sphere
   BranchGroup bg = new BranchGroup();
   // create an Appearance for the Sphere.
   // The Appearance object controls various rendering
   // options for the Sphere geometry.
   Appearance app = new Appearance();
   // assign a Material to the Appearance. For the Sphere
   // to respond to the light in the scene it must have a Material.
   // Assign some colors to the Material and a shininess setting
   // that controls how reflective the surface is to lighting.
   Color3f objColor = new Color3f(0.8f, 0.2f, 1.0f);
   Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
   app.setMaterial(new Material(objColor, black, objColor, black, 80.0f));
   // create a Sphere with a radius of 0.1
   // and associate the Appearance that we described.
   // the option GENERATE_NORMALS is required to ensure that the
   // Sphere responds correctly to lighting.
   Sphere sphere = new Sphere(0.1f, Primitive.GENERATE_NORMALS, app);
   // add the sphere to the BranchGroup to wire
   // it into the scene.
   bg.addChild(sphere);
   return bg;
 }
 /*
  * Add a directional light to the BranchGroup.
  */
 public void addLights(BranchGroup bg) {
   // create the color for the light
   Color3f color = new Color3f(1.0f, 1.0f, 0.0f);
   // create a vector that describes the direction that
   // the light is shining.
   Vector3f direction = new Vector3f(-1.0f, -1.0f, -1.0f);
   // create the directional light with the color and direction
   DirectionalLight light = new DirectionalLight(color, direction);
   // set the volume of influence of the light.
   // Only objects within the Influencing Bounds
   // will be illuminated.
   light.setInfluencingBounds(getBoundingSphere());
   // add the light to the BranchGroup
   bg.addChild(light);
 }
 /*
  * Create some Background geometry to use as a backdrop for the application.
  * Here we create a Sphere that will enclose the entire scene and apply a
  * texture image onto the inside of the Sphere to serve as a graphical
  * backdrop for the scene.
  */
 public BranchGroup createBackground() {
   // create a parent BranchGroup for the Background
   BranchGroup backgroundGroup = new BranchGroup();
   // create a new Background node
   Background back = new Background();
   // set the range of influence of the background
   back.setApplicationBounds(getBoundingSphere());
   // create a BranchGroup that will hold
   // our Sphere geometry
   BranchGroup bgGeometry = new BranchGroup();
   // create an appearance for the Sphere
   Appearance app = new Appearance();
   // load a texture image using the Java 3D texture loader
   Texture tex = new TextureLoader("back.jpg", this).getTexture();
   // apply the texture to the Appearance
   app.setTexture(tex);
   // create the Sphere geometry with radius 1.0
   // we tell the Sphere to generate texture coordinates
   // to enable the texture image to be rendered
   // and because we are *inside* the Sphere we have to generate
   // Normal coordinates inwards or the Sphere will not be visible.
   Sphere sphere = new Sphere(1.0f, Primitive.GENERATE_TEXTURE_COORDS
       | Primitive.GENERATE_NORMALS_INWARD, app);
   // start wiring everything together
   // add the Sphere to its parent BranchGroup
   bgGeometry.addChild(sphere);
   // assign the BranchGroup to the Background as geometry.
   back.setGeometry(bgGeometry);
   // add the Background node to its parent BranchGroup
   backgroundGroup.addChild(back);
   return backgroundGroup;
 }
 /*
  * Create a behavior to move child nodes along the X-axis. The behavior is
  * added to the BranchGroup bg, whereas any nodes added to the returned
  * TransformGroup will be effected by the behavior.
  */
 public TransformGroup createBehaviors(BranchGroup bg) {
   // create a TransformGroup.
   //
   // A TransformGroup is a Group node (can have children)
   // and contains a Transform3D member.
   //
   // The Transform3D member contains a 4x4 transformation matrix
   // that is applied during rendering to all the TransformGroup"s
   // child nodes. The 4x4 matrix can describe:
   // scaling, translation and rotation in one neat package!
   // enable the TRANSFORM_WRITE capability so that
   // our behavior code can modify it at runtime
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   // create a new Transform3D that will describe
   // the direction we want to move.
   Transform3D xAxis = new Transform3D();
   // create an Alpha object.
   // The Alpha object describes a function against time.
   // The Alpha will output a value that ranges between 0 and 1
   // using the time parameters (in milliseconds).
   Alpha xAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE
       | Alpha.INCREASING_ENABLE, 1000, 1000, 5000, 1000, 1000, 10000,
       2000, 4000);
   // create a PositionInterpolator
   // The PositionInterpolator will modify the translation components
   // of a TransformGroup"s Transform3D (objTrans) based on the output
   // from the Alpha. In this case the movement will range from
   // -0.8 along the X-axis with Alpha=0 to X=0.8 when Alpha=1.
   PositionInterpolator posInt = new PositionInterpolator(xAlpha,
       objTrans, xAxis, -0.8f, 0.8f);
   // set the range of influence of the PositionInterpolator
   posInt.setSchedulingBounds(getBoundingSphere());
   // wire the PositionInterpolator into its parent
   // TransformGroup. Just like rendering nodes behaviors
   // must be added to the scenegraph.
   objTrans.addChild(posInt);
   // add the TransformGroup to its parent BranchGroup
   bg.addChild(objTrans);
   // we return the TransformGroup with the
   // behavior attached so that we can add nodes to it
   // (which will be effected by the PositionInterpolator).
   return objTrans;
 }
 /*
  * Return a BoundingSphere that describes the volume of the scene.
  */
 BoundingSphere getBoundingSphere() {
   return new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 200.0);
 }
 /*
  * main entry point for the Application.
  */
 public static void main(String[] args) {
   SimpleTest simpleTest = new SimpleTest();
 }

}


      </source>
   
  
 
  



Scenegraph that illustrates many of the Java 3D scenegraph Nodes

   <source lang="java">

/**********************************************************

Copyright (C) 2001   Daniel Selman
First distributed with the book "Java 3D Programming"
by Daniel Selman and published by Manning Publications.
http://manning.ru/selman
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
The license can be found on the WWW at:
http://www.fsf.org/copyleft/gpl.html
Or by writing to:
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
Authors can be contacted at:
Daniel Selman: daniel@selman.org
If you make changes you think others would like, please 
contact one of the authors or someone at the 
www.j3d.org web site.
**************************************************************/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Font; import java.awt.GraphicsConfigTemplate; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.io.File; import java.net.URL; import javax.media.j3d.Alpha; import javax.media.j3d.Appearance; import javax.media.j3d.AudioDevice; import javax.media.j3d.Background; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.Bounds; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.media.j3d.Group; import javax.media.j3d.Link; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.Node; import javax.media.j3d.OrderedGroup; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.PickBounds; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.SharedGroup; import javax.media.j3d.Switch; import javax.media.j3d.SwitchValueInterpolator; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.View; import javax.media.j3d.ViewPlatform; import javax.media.j3d.VirtualUniverse; import javax.media.j3d.WakeupCondition; import javax.media.j3d.WakeupCriterion; import javax.media.j3d.WakeupOnElapsedFrames; import javax.media.j3d.WakeupOr; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.geometry.Text2D; import com.sun.j3d.utils.picking.PickResult; import com.sun.j3d.utils.picking.PickTool; /**

* This example creates a scenegraph that illustrates many of the Java 3D
* scenegraph Nodes. These are:
* <p>
* 
* Group Nodes:
* BranchGroup, (implemented)
* OrderedGroup, (implemented)
* Primitive, (implemented)
* SharedGroup, (implemented)
* Switch, (implemented)
* TransformGroup (implemented)
*
* Leaf Nodes:
* Background, (implemented)
* Behavior, (implemented)
* BoundingLeaf,
* Clip,
* Fog,
* Light,
* Link, (implemented)
* Morph,
* Shape3D, (implemented)
* Sound,
* Soundscape,
* ViewPlatform (implemented)
*/

public class NodesTest extends Java3dApplet {

 private static final int m_kWidth = 400;
 private static final int m_kHeight = 400;
 static int m_nLabelNumber = 0;
 public NodesTest() {
   initJava3d();
 }
 protected BranchGroup createSceneBranchGroup() {
   BranchGroup objRoot = super.createSceneBranchGroup();
   double labelScale = 20;
   // create the top level Switch Node
   // we will use the Switch Node to switch the
   // other Nodes on and off.
   // 1: Switch
   Switch switchGroup = new Switch();
   switchGroup.setCapability(Switch.ALLOW_SWITCH_WRITE);
   switchGroup.addChild(createLabel("1. Switch Label", labelScale));
   // 2: BranchGroup
   BranchGroup branchGroup = new BranchGroup();
   branchGroup.addChild(createLabel("2. BranchGroup", labelScale));
   switchGroup.addChild(branchGroup);
   // 3: OrderedGroup,
   OrderedGroup orderedGroup = new OrderedGroup();
   orderedGroup.addChild(createLabel("3. OrderedGroup", labelScale));
   orderedGroup.addChild(createLabel("Child 1", labelScale));
   orderedGroup.addChild(createLabel("Child 2", labelScale));
   switchGroup.addChild(orderedGroup);
   // 4: SharedGroup,
   SharedGroup sharedGroup1 = new SharedGroup();
   sharedGroup1.addChild(createLabel("4. Shared Group 1", labelScale));
   switchGroup.addChild(new Link(sharedGroup1));
   // 5: Primitive,
   BranchGroup primitiveGroup = new BranchGroup();
   primitiveGroup.addChild(createLabel("5. Primitive", labelScale));
   primitiveGroup.addChild(new Sphere(2));
   switchGroup.addChild(primitiveGroup);
   // 6: TransformGroup
   TransformGroup transformGroup = new TransformGroup();
   transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
   Transform3D yAxis = new Transform3D();
   Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
       4000, 0, 0, 0, 0, 0);
   RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,
       transformGroup, yAxis, 0.0f, (float) Math.PI * 2.0f);
   rotator.setSchedulingBounds(createApplicationBounds());
   transformGroup.addChild(rotator);
   transformGroup.addChild(new ColorCube(2));
   transformGroup.addChild(createLabel("6. TransformGroup", labelScale));
   switchGroup.addChild(transformGroup);
   // 7: add another copy of the shared group
   switchGroup.addChild(new Link(sharedGroup1));
   // create a SwitchValueInterpolator to
   // cycle through the child nodes in the Switch Node
   Alpha switchAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 10000,
       0, 0, 0, 0, 0);
   SwitchValueInterpolator switchInterpolator = new SwitchValueInterpolator(
       switchAlpha, switchGroup);
   switchInterpolator.setSchedulingBounds(createApplicationBounds());
   switchInterpolator.setEnable(true);
   // WARNING: do not add the SwitchValueInterpolator to the Switch Node!
   objRoot.addChild(switchInterpolator);
   // finally add the Switch Node
   objRoot.addChild(switchGroup);
   return objRoot;
 }
 // creates a Text2D label and scales it
 // the method shifts each label created downwards.
 // Note that the labels on adjacent lines will overlap
 // so we can illustrate the function of the OrderedGroup
 TransformGroup createLabel(String szText, double scale) {
   Color3f colorText = new Color3f();
   int nFontSizeText = 10;
   Text2D label3D = new Text2D(szText, colorText, "SansSerif",
       nFontSizeText, Font.PLAIN);
   TransformGroup tg = new TransformGroup();
   Transform3D t3d = new Transform3D();
   t3d.setTranslation(new Vector3d(-8, 0.5 * (1 - m_nLabelNumber), 0));
   t3d.setScale(scale);
   tg.setTransform(t3d);
   tg.addChild(label3D);
   m_nLabelNumber++;
   return tg;
 }
 public static void main(String[] args) {
   NodesTest nodesTest = new NodesTest();
   nodesTest.saveCommandLineArguments(args);
   new MainFrame(nodesTest, m_kWidth, m_kHeight);
 }

} /**

* This behavior detects collisions between the branch of a scene, and a
* collision object. The Java 3D 1.2 picking utilities are used to implement
* collision detection. The objects in the scene that are collidable should have
* their user data set. The collision object"s user data is used to ignore
* collisions between the object and itself.
* 
* When a collision is detected the trajectory of the collision object is
* reversed (plus a small random factor) and an Appearance object is modified.
* 
* When a collision is not detected the collision object is moved along its
* current trajectory and the Appearance color is reset.
* 
* Colision checking is run after every frame.
*  
*/

class CollisionBehavior extends Behavior {

 // the wake up condition for the behavior
 protected WakeupCondition m_WakeupCondition = null;
 // how often we check for a collision
 private static final int ELAPSED_FRAME_COUNT = 1;
 // the branch that we check for collisions
 private BranchGroup pickRoot = null;
 // the collision object that we are controlling
 private TransformGroup collisionObject = null;
 // the appearance object that we are controlling
 private Appearance objectAppearance = null;
 // cached PickBounds object used for collision detection
 private PickBounds pickBounds = null;
 // cached Material objects that define the collided and missed colors
 private Material collideMaterial = null;
 private Material missMaterial = null;
 // the current trajectory of the object
 private Vector3d incrementVector = null;
 // the current position of the object
 private Vector3d positionVector = null;
 public CollisionBehavior(BranchGroup pickRoot,
     TransformGroup collisionObject, Appearance app, Vector3d posVector,
     Vector3d incVector) {
   // save references to the objects
   this.pickRoot = pickRoot;
   this.collisionObject = collisionObject;
   this.objectAppearance = app;
   incrementVector = incVector;
   positionVector = posVector;
   // create the WakeupCriterion for the behavior
   WakeupCriterion criterionArray[] = new WakeupCriterion[1];
   criterionArray[0] = new WakeupOnElapsedFrames(ELAPSED_FRAME_COUNT);
   objectAppearance.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
   collisionObject.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   collisionObject.setCapability(Node.ALLOW_BOUNDS_READ);
   // save the WakeupCriterion for the behavior
   m_WakeupCondition = new WakeupOr(criterionArray);
 }
 public void initialize() {
   // apply the initial WakeupCriterion
   wakeupOn(m_WakeupCondition);
   Color3f objColor = new Color3f(1.0f, 0.1f, 0.2f);
   Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
   collideMaterial = new Material(objColor, black, objColor, black, 80.0f);
   objColor = new Color3f(0.0f, 0.1f, 0.8f);
   missMaterial = new Material(objColor, black, objColor, black, 80.0f);
   objectAppearance.setMaterial(missMaterial);
 }
 protected void onCollide() {
   objectAppearance.setMaterial(collideMaterial);
   incrementVector.negate();
   // add a little randomness
   incrementVector.x += (Math.random() - 0.5) / 20.0;
   incrementVector.y += (Math.random() - 0.5) / 20.0;
   incrementVector.z += (Math.random() - 0.5) / 20.0;
 }
 protected void onMiss() {
   objectAppearance.setMaterial(missMaterial);
 }
 protected void moveCollisionObject() {
   Transform3D t3d = new Transform3D();
   positionVector.add(incrementVector);
   t3d.setTranslation(positionVector);
   collisionObject.setTransform(t3d);
 }
 public boolean isCollision(PickResult[] resultArray) {
   if (resultArray == null || resultArray.length == 0)
     return false;
   // we use the user data on the nodes to ignore the
   // case of the collisionObject having collided with itself!
   // the user data also gives us a good mechanism for reporting the
   // collisions.
   for (int n = 0; n < resultArray.length; n++) {
     Object userData = resultArray[n].getObject().getUserData();
     if (userData != null && userData instanceof String) {
       // check that we are not colliding with ourselves...
       if (((String) userData).equals((String) collisionObject
           .getUserData()) == false) {
         System.out.println("Collision between: "
             + collisionObject.getUserData() + " and: "
             + userData);
         return true;
       }
     }
   }
   return false;
 }
 public void processStimulus(java.util.Enumeration criteria) {
   while (criteria.hasMoreElements()) {
     WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();
     // every N frames, check for a collision
     if (wakeUp instanceof WakeupOnElapsedFrames) {
       // create a PickBounds
       PickTool pickTool = new PickTool(pickRoot);
       pickTool.setMode(PickTool.BOUNDS);
       BoundingSphere bounds = (BoundingSphere) collisionObject
           .getBounds();
       pickBounds = new PickBounds(new BoundingSphere(new Point3d(
           positionVector.x, positionVector.y, positionVector.z),
           bounds.getRadius()));
       pickTool.setShape(pickBounds, new Point3d(0, 0, 0));
       PickResult[] resultArray = pickTool.pickAll();
       if (isCollision(resultArray))
         onCollide();
       else
         onMiss();
       moveCollisionObject();
     }
   }
   // assign the next WakeUpCondition, so we are notified again
   wakeupOn(m_WakeupCondition);
 }

} /*******************************************************************************

* Copyright (C) 2001 Daniel Selman
* 
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.ru/selman
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
* 
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
* 
* Authors can be contacted at: Daniel Selman: daniel@selman.org
* 
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/

//***************************************************************************** /**

* Java3dApplet
* 
* Base class for defining a Java 3D applet. Contains some useful methods for
* defining views and scenegraphs etc.
* 
* @author Daniel Selman
* @version 1.0
*/

//***************************************************************************** abstract class Java3dApplet extends Applet {

 public static int m_kWidth = 300;
 public static int m_kHeight = 300;
 protected String[] m_szCommandLineArray = null;
 protected VirtualUniverse m_Universe = null;
 protected BranchGroup m_SceneBranchGroup = null;
 protected Bounds m_ApplicationBounds = null;
 //  protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;
 public Java3dApplet() {
 }
 public boolean isApplet() {
   try {
     System.getProperty("user.dir");
     System.out.println("Running as Application.");
     return false;
   } catch (Exception e) {
   }
   System.out.println("Running as Applet.");
   return true;
 }
 public URL getWorkingDirectory() throws java.net.MalformedURLException {
   URL url = null;
   try {
     File file = new File(System.getProperty("user.dir"));
     System.out.println("Running as Application:");
     System.out.println("   " + file.toURL());
     return file.toURL();
   } catch (Exception e) {
   }
   System.out.println("Running as Applet:");
   System.out.println("   " + getCodeBase());
   return getCodeBase();
 }
 public VirtualUniverse getVirtualUniverse() {
   return m_Universe;
 }
 //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
 //return m_Java3dTree;
 //  }
 public Locale getFirstLocale() {
   java.util.Enumeration e = m_Universe.getAllLocales();
   if (e.hasMoreElements() != false)
     return (Locale) e.nextElement();
   return null;
 }
 protected Bounds getApplicationBounds() {
   if (m_ApplicationBounds == null)
     m_ApplicationBounds = createApplicationBounds();
   return m_ApplicationBounds;
 }
 protected Bounds createApplicationBounds() {
   m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   return m_ApplicationBounds;
 }
 protected Background createBackground() {
   Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
   back.setApplicationBounds(createApplicationBounds());
   return back;
 }
 public void initJava3d() {
   //  m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
   m_Universe = createVirtualUniverse();
   Locale locale = createLocale(m_Universe);
   BranchGroup sceneBranchGroup = createSceneBranchGroup();
   ViewPlatform vp = createViewPlatform();
   BranchGroup viewBranchGroup = createViewBranchGroup(
       getViewTransformGroupArray(), vp);
   createView(vp);
   Background background = createBackground();
   if (background != null)
     sceneBranchGroup.addChild(background);
   //    m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
   //  m_Java3dTree.recursiveApplyCapability(viewBranchGroup);
   locale.addBranchGraph(sceneBranchGroup);
   addViewBranchGroup(locale, viewBranchGroup);
   onDoneInit();
 }
 protected void onDoneInit() {
   //  m_Java3dTree.updateNodes(m_Universe);
 }
 protected double getScale() {
   return 1.0;
 }
 public TransformGroup[] getViewTransformGroupArray() {
   TransformGroup[] tgArray = new TransformGroup[1];
   tgArray[0] = new TransformGroup();
   // move the camera BACK a little...
   // note that we have to invert the matrix as
   // we are moving the viewer
   Transform3D t3d = new Transform3D();
   t3d.setScale(getScale());
   t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
   t3d.invert();
   tgArray[0].setTransform(t3d);
   return tgArray;
 }
 protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
   locale.addBranchGraph(bg);
 }
 protected Locale createLocale(VirtualUniverse u) {
   return new Locale(u);
 }
 protected BranchGroup createSceneBranchGroup() {
   m_SceneBranchGroup = new BranchGroup();
   return m_SceneBranchGroup;
 }
 protected View createView(ViewPlatform vp) {
   View view = new View();
   PhysicalBody pb = createPhysicalBody();
   PhysicalEnvironment pe = createPhysicalEnvironment();
   AudioDevice audioDevice = createAudioDevice(pe);
   if (audioDevice != null) {
     pe.setAudioDevice(audioDevice);
     audioDevice.initialize();
   }
   view.setPhysicalEnvironment(pe);
   view.setPhysicalBody(pb);
   if (vp != null)
     view.attachViewPlatform(vp);
   view.setBackClipDistance(getBackClipDistance());
   view.setFrontClipDistance(getFrontClipDistance());
   Canvas3D c3d = createCanvas3D();
   view.addCanvas3D(c3d);
   addCanvas3D(c3d);
   return view;
 }
 protected PhysicalBody createPhysicalBody() {
   return new PhysicalBody();
 }
 protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
   JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);
   if (javaSoundMixer == null)
     System.out.println("create of audiodevice failed");
   return javaSoundMixer;
 }
 protected PhysicalEnvironment createPhysicalEnvironment() {
   return new PhysicalEnvironment();
 }
 protected float getViewPlatformActivationRadius() {
   return 100;
 }
 protected ViewPlatform createViewPlatform() {
   ViewPlatform vp = new ViewPlatform();
   vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
   vp.setActivationRadius(getViewPlatformActivationRadius());
   return vp;
 }
 protected Canvas3D createCanvas3D() {
   GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
   gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
   GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
       .getScreenDevices();
   Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
   c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
   return c3d;
 }
 protected int getCanvas3dWidth(Canvas3D c3d) {
   return m_kWidth;
 }
 protected int getCanvas3dHeight(Canvas3D c3d) {
   return m_kHeight;
 }
 protected double getBackClipDistance() {
   return 100.0;
 }
 protected double getFrontClipDistance() {
   return 1.0;
 }
 protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray,
     ViewPlatform vp) {
   BranchGroup vpBranchGroup = new BranchGroup();
   if (tgArray != null && tgArray.length > 0) {
     Group parentGroup = vpBranchGroup;
     TransformGroup curTg = null;
     for (int n = 0; n < tgArray.length; n++) {
       curTg = tgArray[n];
       parentGroup.addChild(curTg);
       parentGroup = curTg;
     }
     tgArray[tgArray.length - 1].addChild(vp);
   } else
     vpBranchGroup.addChild(vp);
   return vpBranchGroup;
 }
 protected void addCanvas3D(Canvas3D c3d) {
   setLayout(new BorderLayout());
   add(c3d, BorderLayout.CENTER);
   doLayout();
 }
 protected VirtualUniverse createVirtualUniverse() {
   return new VirtualUniverse();
 }
 protected void saveCommandLineArguments(String[] szArgs) {
   m_szCommandLineArray = szArgs;
 }
 protected String[] getCommandLineArguments() {
   return m_szCommandLineArray;
 }

}


      </source>
   
  
 
  



Simple Universe

   <source lang="java">

/*

* @(#)HelloUniverse.java 1.17 02/10/21 13:58:47
* 
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: -
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. - Redistribution in binary
* form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided
* with the distribution.
* 
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* 
* 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.
* 
* You acknowledge that Software is not designed,licensed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Button; import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GridLayout; import java.awt.Panel; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; import java.util.Enumeration; import javax.media.j3d.Alpha; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.InputDevice; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Sensor; import javax.media.j3d.SensorRead; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.WakeupOnElapsedFrames; import javax.vecmath.Point3d; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.universe.SimpleUniverse; public class HelloUniverse extends Applet {

 private SimpleUniverse u = null;
 public BranchGroup createSceneGraph() {
   BranchGroup objRoot = new BranchGroup();
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objRoot.addChild(objTrans);
   objTrans.addChild(new ColorCube(0.2));
   Transform3D yAxis = new Transform3D();
   Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
       4000, 0, 0, 0, 0, 0);
   RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,
       objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   rotator.setSchedulingBounds(bounds);
   objTrans.addChild(rotator);
   return objRoot;
 }
 public HelloUniverse() {
 }
 public void init() {
   // These are the string arguments given to the VirtualInputDevice
   // constructor. These are settable parameters. Look in the
   // VirtualInputDevice constructor for a complete list.
   String[] args = new String[10];
   args[0] = "printvalues";
   args[1] = "true";
   args[2] = "yscreeninitloc";
   args[3] = "50";
   args[4] = null;
   InputDevice device = new VirtualInputDevice(args);
   // now create the HelloUniverse Canvas
   setLayout(new BorderLayout());
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   Canvas3D c = new Canvas3D(config);
   add("Center", c);
   // Create a simple scene and attach it to the virtual universe
   BranchGroup scene = createSceneGraph();
   u = new SimpleUniverse(c);
   // The InputDevice must be initialized before registering it
   // with the PhysicalEnvironment object.
   device.initialize();
   // Register the VirtualInputDevice with Java 3D
   u.getViewer().getPhysicalEnvironment().addInputDevice(device);
   TransformGroup viewTrans = u.getViewingPlatform()
       .getViewPlatformTransform();
   SensorBehavior s = new SensorBehavior(viewTrans, device.getSensor(0));
   s.setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       Float.MAX_VALUE));
   scene.addChild(s);
   u.addBranchGraph(scene);
 }
 public void destroy() {
   u.cleanup();
 }
 public static void main(String[] args) {
   new MainFrame(new HelloUniverse(), 350, 350);
 }

} class VirtualInputDevice implements InputDevice {

 private Vector3f position = new Vector3f();
 private Transform3D newTransform = new Transform3D();
 Sensor sensors[] = new Sensor[1];
 // The wheel controls control the view platform orientation
 private RotationControls rotControls;
 // The button position controls control the view platform position
 private PositionControls positionControls;
 private Transform3D rotTransX = new Transform3D();
 private Transform3D rotTransY = new Transform3D();
 private Transform3D rotTransZ = new Transform3D();
 private Vector3f initPos = new Vector3f();
 private int processingMode;
 private SensorRead sensorRead = new SensorRead();
 // These are the settable parameters.
 private boolean printvalues;
 private int xscreeninitloc;
 private int yscreeninitloc;
 private int xscreensize;
 private int yscreensize;
 private float xobjinitloc;
 private float yobjinitloc;
 private float zobjinitloc;
 private float xaxisrotinit;
 private float yaxisrotinit;
 private float zaxisrotinit;
 /*
  * Create a device, and use the string arguments in args to construct the
  * device with user preferences.
  */
 public VirtualInputDevice(String[] args) {
   // default user-definable values
   printvalues = false;
   xscreeninitloc = 400;
   yscreeninitloc = 0;
   xscreensize = 400;
   yscreensize = 200;
   xobjinitloc = 0.0f;
   yobjinitloc = 0.0f;
   zobjinitloc = 2.2f;
   xaxisrotinit = 0.0f;
   yaxisrotinit = 0.0f;
   zaxisrotinit = 0.0f;
   for (int i = 0; i < args.length; i += 2) {
     if (args[i] == null)
       break;
     else if (args[i] == "printvalues")
       printvalues = (Boolean.valueOf(args[i + 1])).booleanValue();
     else if (args[i] == "xscreeninitloc")
       xscreeninitloc = (Integer.valueOf(args[i + 1])).intValue();
     else if (args[i] == "yscreeninitloc")
       yscreeninitloc = (Integer.valueOf(args[i + 1])).intValue();
     else if (args[i] == "xscreensize")
       xscreensize = (Integer.valueOf(args[i + 1])).intValue();
     else if (args[i] == "yscreensize")
       yscreensize = (Integer.valueOf(args[i + 1])).intValue();
     else if (args[i] == "xobjinitloc")
       xobjinitloc = (Float.valueOf(args[i + 1])).floatValue();
     else if (args[i] == "yobjinitloc")
       yobjinitloc = (Float.valueOf(args[i + 1])).floatValue();
     else if (args[i] == "zobjinitloc")
       zobjinitloc = (Integer.valueOf(args[i + 1])).floatValue();
   }
   if (printvalues == true) {
     System.out.println("Initial values for VirtualInputDevice:");
     System.out.println("xscreeninitloc = " + xscreeninitloc);
     System.out.println("yscreeninitloc = " + yscreeninitloc);
     System.out.println("xscreeninitsize = " + xscreensize);
     System.out.println("yscreeninitsize = " + yscreensize);
     System.out.println("xobjinitloc = " + xobjinitloc);
     System.out.println("yobjinitloc = " + yobjinitloc);
     System.out.println("zobjinitloc = " + zobjinitloc);
     System.out.println("xaxisrotinit = " + xaxisrotinit);
     System.out.println("yaxisrotinit = " + yaxisrotinit);
     System.out.println("zaxisrotinit = " + zaxisrotinit);
   }
   // initialize the InputDevice GUI
   Frame deviceFrame = new Frame();
   deviceFrame.setSize(xscreensize, yscreensize);
   deviceFrame.setLocation(xscreeninitloc, yscreeninitloc);
   deviceFrame.setTitle("Virtual Input Device");
   ButtonPositionControls positionControls;
   // initialize position with initial x, y, and z position
   positionControls = new ButtonPositionControls(xobjinitloc, yobjinitloc,
       zobjinitloc);
   WheelControls rotControls;
   // initialize rotations with initial angles in radians)
   rotControls = new WheelControls(xaxisrotinit, yaxisrotinit,
       zaxisrotinit);
   positionControls.setDevice(this);
   Panel devicePanel = new Panel();
   devicePanel.setLayout(new BorderLayout());
   devicePanel.add("East", positionControls);
   devicePanel.add("West", rotControls);
   deviceFrame.add(devicePanel);
   deviceFrame.pack();
   deviceFrame.setVisible(true);
   initPos.set(xobjinitloc, yobjinitloc, zobjinitloc);
   this.positionControls = positionControls;
   this.rotControls = rotControls;
   // default processing mode
   processingMode = InputDevice.DEMAND_DRIVEN;
   sensors[0] = new Sensor(this);
 }
 public void close() {
 }
 public int getProcessingMode() {
   return processingMode;
 }
 public int getSensorCount() {
   return sensors.length;
 }
 public Sensor getSensor(int sensorIndex) {
   return sensors[sensorIndex];
 }
 public boolean initialize() {
   return true;
 }
 public void pollAndProcessInput() {
   sensorRead.setTime(System.currentTimeMillis());
   rotTransX.rotX(-rotControls.getXAngle());
   rotTransY.rotY(-rotControls.getYAngle());
   rotTransZ.rotZ(-rotControls.getZAngle());
   positionControls.getPosition(position);
   newTransform.set(position);
   newTransform.mul(rotTransX);
   newTransform.mul(rotTransY);
   newTransform.mul(rotTransZ);
   sensorRead.set(newTransform);
   sensors[0].setNextSensorRead(sensorRead);
 }
 public void processStreamInput() {
 }
 public void setNominalPositionAndOrientation() {
   sensorRead.setTime(System.currentTimeMillis());
   rotTransX.rotX(xaxisrotinit);
   rotTransY.rotY(yaxisrotinit);
   rotTransZ.rotZ(zaxisrotinit);
   position.set(initPos);
   newTransform.set(position);
   newTransform.mul(rotTransX);
   newTransform.mul(rotTransY);
   newTransform.mul(rotTransZ);
   sensorRead.set(newTransform);
   sensors[0].setNextSensorRead(sensorRead);
   rotControls.reset();
   positionControls.setPosition(initPos);
 }
 public void setProcessingMode(int mode) {
   // A typical driver might implement only one of these modes, and
   // throw an exception when there is an attempt to switch modes.
   // However, this example allows one to use any processing mode.
   switch (mode) {
   case InputDevice.DEMAND_DRIVEN:
   case InputDevice.NON_BLOCKING:
   case InputDevice.BLOCKING:
     processingMode = mode;
     break;
   default:
     throw new IllegalArgumentException("Processing mode must "
         + "be one of DEMAND_DRIVEN, NON_BLOCKING, or BLOCKING");
   }
 }

} class SensorBehavior extends Behavior {

 private WakeupOnElapsedFrames conditions = new WakeupOnElapsedFrames(0);
 private TransformGroup transformGroup;
 private Sensor sensor;
 private Transform3D transform = new Transform3D();
 public SensorBehavior(TransformGroup tg, Sensor sensor) {
   transformGroup = tg;
   this.sensor = sensor;
 }
 public void initialize() {
   wakeupOn(conditions);
 }
 public void processStimulus(Enumeration criteria) {
   sensor.getRead(transform);
   transformGroup.setTransform(transform);
   wakeupOn(conditions);
 }

} //Classes that implement this interface must be a //subclass of java.awt.ruponent interface PositionControls {

 /**
  * Get the position
  */
 public void getPosition(Vector3f pos);
 /**
  * Set the position
  */
 public void setPosition(Vector3f pos);
 /**
  * Increment added to position each time mouse is pressed or if the mouse is
  * held down each time the Sensor is read
  */
 public void setStepRate(float stepRate);

} //Classes that implement this interface must be a subclass //of java.awt.ruponent interface RotationControls {

 /**
  * Get the angle of Rotation around the X Axis
  */
 public abstract float getXAngle();
 /**
  * Get the angle or Rotation around the Y Axis
  */
 public abstract float getYAngle();
 /**
  * Get the angle or Rotation around the Z Axis
  */
 public abstract float getZAngle();
 /**
  * Reset angles to original angle.
  */
 public abstract void reset();

} class WheelControls extends Canvas implements RotationControls,

   MouseMotionListener, MouseListener {
 private final static int NONE = 0;
 private final static int SLIDE_Y = 1;
 private final static int SLIDE_X = 2;
 private final static int SLIDE_Z = 3;
 private int mode = NONE;
 private Dimension size;
 private int thickness;
 private int diameter;
 private int space;
 private int pipSize;
 private int pipOffset; // Amount pip is below wheel
 private int margin; // Margin between edge of Canvas and
 // controls
 private Polygon yPip;
 private Rectangle yBackClip;
 private Polygon xPip;
 private Rectangle xBackClip;
 private Polygon zPip;
 private Rectangle yArea;
 private Rectangle xArea;
 private Rectangle zArea;
 private Point oldMousePos = new Point();
 float yAngle = 0.0f;
 float xAngle = 0.0f;
 float zAngle = 0.0f;
 float yOrigAngle;
 float xOrigAngle;
 float zOrigAngle;
 float angleStep = (float) Math.PI / 30.0f;
 public WheelControls() {
   this(0.0f, 0.0f, 0.0f);
 }
 public WheelControls(float rotX, float rotY, float rotZ) {
   size = new Dimension(200, 200);
   xAngle = constrainAngle(rotX);
   yAngle = constrainAngle(rotY);
   zAngle = constrainAngle(rotZ);
   yOrigAngle = yAngle;
   xOrigAngle = xAngle;
   zOrigAngle = zAngle;
   setSizes();
   yPip = new Polygon();
   yPip.addPoint(0, 0);
   yPip.addPoint(-pipSize / 2, pipSize);
   yPip.addPoint(pipSize / 2, pipSize);
   xPip = new Polygon();
   xPip.addPoint(0, 0);
   xPip.addPoint(pipSize, -pipSize / 2);
   xPip.addPoint(pipSize, pipSize / 2);
   zPip = new Polygon();
   zPip.addPoint(diameter / 2, pipOffset);
   zPip.addPoint(diameter / 2 - pipSize / 2, pipOffset - pipSize);
   zPip.addPoint(diameter / 2 + pipSize / 2, pipOffset - pipSize);
   addMouseListener(this);
   addMouseMotionListener(this);
 }
 private void setSizes() {
   margin = 10;
   int width = size.width - margin * 2;
   thickness = width * 7 / 100;
   diameter = width * 70 / 100;
   space = width * 10 / 100;
   pipSize = width * 7 / 100;
   pipOffset = thickness / 2;
 }
 public void paint(Graphics g) {
   Graphics2D g2 = (Graphics2D) g;
   g.drawOval(margin, margin, diameter, diameter);
   zArea = new Rectangle(margin, margin, diameter, diameter);
   drawZPip(g2, zAngle);
   g.drawRect(margin, margin + diameter + space, diameter, thickness); // Y
                                     // Wheel
   yArea = new Rectangle(margin, margin + diameter + space, margin
       + diameter, thickness + pipOffset);
   yBackClip = new Rectangle(margin - thickness, margin + diameter + space
       + thickness, margin + diameter + thickness * 2, thickness);
   drawYPip(g2, yAngle);
   g.drawRect(margin + diameter + space, margin, thickness, diameter); // X
                                     // Wheel
   xArea = new Rectangle(margin + diameter + space, margin, thickness
       + pipOffset, margin + diameter);
   xBackClip = new Rectangle(margin + diameter + space + thickness, margin
       - thickness, thickness, margin + diameter + thickness * 2);
   drawXPip(g2, xAngle);
 }
 public float getXAngle() {
   return xAngle;
 }
 public float getYAngle() {
   return yAngle;
 }
 public float getZAngle() {
   return zAngle;
 }
 public void reset() {
   // Overwrite the old pip
   drawYPip((Graphics2D) (this.getGraphics()), yAngle);
   yAngle = yOrigAngle;
   // Draw the new Pip
   drawYPip((Graphics2D) (this.getGraphics()), yAngle);
   // Overwrite the old pip
   drawXPip((Graphics2D) (this.getGraphics()), xAngle);
   xAngle = xOrigAngle;
   // Draw the new Pip
   drawXPip((Graphics2D) (this.getGraphics()), xAngle);
   drawZPip((Graphics2D) (this.getGraphics()), zAngle);
   zAngle = zOrigAngle;
   drawZPip((Graphics2D) (this.getGraphics()), zAngle);
   oldMousePos.setLocation(0, 0);
 }
 private void drawXPip(Graphics2D g2, float angle) {
   AffineTransform trans = new AffineTransform();
   int y;
   int xOrig = margin + diameter + space;
   int yOrig = margin;
   Color origColor = g2.getColor();
   if (angle <= Math.PI) {
     y = yOrig
         + diameter
         - (int) ((Math.abs(angle - Math.PI / 2) / (Math.PI / 2))
             * diameter / 2);
   } else
     y = yOrig
         + (int) ((Math.abs((angle - Math.PI * 1.5)) / (Math.PI / 2))
             * diameter / 2);
   if (angle < Math.PI / 2 || angle > Math.PI * 1.5)
     g2.setColor(Color.red); // Infront of wheel
   else {
     g2.setColor(Color.black); // Behind Wheel
     g2.setClip(xBackClip);
   }
   g2.setXORMode(getBackground());
   trans.setToTranslation(xOrig + pipOffset, y);
   g2.setTransform(trans);
   g2.fillPolygon(xPip);
   // Reset graphics context
   trans.setToIdentity();
   g2.setTransform(trans);
   g2.setColor(origColor);
   g2.setPaintMode();
 }
 private void drawYPip(Graphics2D g2, float angle) {
   AffineTransform trans = new AffineTransform();
   int x;
   int xOrig = margin;
   int yOrig = margin + diameter + space;
   Color origColor = g2.getColor();
   if (angle <= Math.PI) {
     x = xOrig
         + diameter
         - (int) ((Math.abs(angle - Math.PI / 2) / (Math.PI / 2))
             * diameter / 2);
   } else
     x = xOrig
         + (int) ((Math.abs((angle - Math.PI * 1.5)) / (Math.PI / 2))
             * diameter / 2);
   if (angle < Math.PI / 2 || angle > Math.PI * 1.5)
     g2.setColor(Color.red); // Infront on wheel
   else {
     g2.setColor(Color.black); // Behind Wheel
     g2.setClip(yBackClip);
   }
   g2.setXORMode(getBackground());
   trans.setToTranslation(x, yOrig + pipOffset);
   g2.setTransform(trans);
   g2.fillPolygon(yPip);
   // Reset graphics context
   trans.setToIdentity();
   g2.setTransform(trans);
   g2.setColor(origColor);
   g2.setPaintMode();
 }
 private void drawZPip(Graphics2D g2, float zAngle) {
   AffineTransform trans = new AffineTransform();
   Color origColor = g2.getColor();
   trans.translate(margin, margin);
   trans.rotate(zAngle, diameter / 2, diameter / 2);
   g2.setXORMode(getBackground());
   g2.setTransform(trans);
   g2.setColor(Color.red);
   g2.fillPolygon(zPip);
   // Reset graphics context
   trans.setToIdentity();
   g2.setTransform(trans);
   g2.setColor(origColor);
   g2.setPaintMode();
 }
 public Dimension getPreferredSize() {
   return size;
 }
 public void setSize(Dimension d) {
   // Set size to smallest dimension
   if (d.width < d.height)
     size.width = size.height = d.width;
   else
     size.width = size.height = d.height;
   setSizes();
 }
 public void mouseClicked(MouseEvent e) {
 }
 public void mouseEntered(MouseEvent e) {
 }
 public void mouseExited(MouseEvent e) {
 }
 public void mousePressed(MouseEvent e) {
   if (yArea.contains(e.getPoint())) {
     mode = SLIDE_Y;
     oldMousePos = e.getPoint();
   } else if (xArea.contains(e.getPoint())) {
     mode = SLIDE_X;
     oldMousePos = e.getPoint();
   } else if (zArea.contains(e.getPoint())) {
     mode = SLIDE_Z;
     oldMousePos = e.getPoint();
   }
 }
 public void mouseReleased(MouseEvent e) {
   mode = NONE;
 }
 public void mouseDragged(MouseEvent e) {
   Point pos = e.getPoint();
   int diffX = pos.x - oldMousePos.x;
   int diffY = pos.y - oldMousePos.y;
   switch (mode) {
   case NONE:
     break;
   case SLIDE_Y:
     // Overwrite the old pip
     drawYPip((Graphics2D) ((Canvas) e.getSource()).getGraphics(),
         yAngle);
     if (diffX < 0)
       yAngle -= angleStep;
     else if (diffX > 0)
       yAngle += angleStep;
     yAngle = constrainAngle(yAngle);
     // Draw the new Pip
     drawYPip((Graphics2D) ((Canvas) e.getSource()).getGraphics(),
         yAngle);
     oldMousePos = pos;
     break;
   case SLIDE_X:
     // Overwrite the old pip
     drawXPip((Graphics2D) ((Canvas) e.getSource()).getGraphics(),
         xAngle);
     if (diffY < 0)
       xAngle -= angleStep;
     else if (diffY > 0)
       xAngle += angleStep;
     xAngle = constrainAngle(xAngle);
     // Draw the new Pip
     drawXPip((Graphics2D) ((Canvas) e.getSource()).getGraphics(),
         xAngle);
     oldMousePos = pos;
     break;
   case SLIDE_Z:
     drawZPip((Graphics2D) ((Canvas) e.getSource()).getGraphics(),
         zAngle);
     if (diffX < 0)
       zAngle -= angleStep;
     else if (diffX > 0)
       zAngle += angleStep;
     zAngle = constrainAngle(zAngle);
     drawZPip((Graphics2D) ((Canvas) e.getSource()).getGraphics(),
         zAngle);
     oldMousePos = pos;
     break;
   default:
     throw (new RuntimeException("Internal Error"));
   }
 }
 public void mouseMoved(MouseEvent e) {
 }
 /**
  * Constrain angle to be 0 <angle <2PI
  */
 private float constrainAngle(float angle) {
   if (angle > (float) Math.PI * 2)
     return angle - (float) Math.PI * 2;
   if (angle < 0.0f)
     return angle + (float) Math.PI * 2;
   return angle;
 }

} class ButtonPositionControls extends Panel implements PositionControls,

   MouseListener {
 private final static int STILL = 0;
 private final static int MOVING_UP = 1;
 private final static int MOVING_DOWN = 2;
 private final static int MOVING_LEFT = 3;
 private final static int MOVING_RIGHT = 4;
 private final static int MOVING_FORWARD = 5;
 private final static int MOVING_BACK = 6;
 // initial mode
 private int mode = STILL;
 Vector3f position = new Vector3f();
 Vector3f orig_position = new Vector3f();
 private Button leftB = new Button("Move Left");
 private Button rightB = new Button("Move Right");
 private Button upB = new Button("Move Up");
 private Button downB = new Button("Move Down");
 private Button forwardB = new Button("Move Forward");
 private Button backwardB = new Button("Move Back");
 private Button reset = new Button("Reset");
 private InputDevice device;
 private float step_rate = 0.0023f; // movement rate per millisecond
 private long time_last_state_change = System.currentTimeMillis();
 // the constructor arguments are the intitial X, Y, and Z positions
 public ButtonPositionControls(float x, float y, float z) {
   // up, down, right, and left movement buttons
   Panel panPanel = new Panel();
   panPanel.setLayout(new BorderLayout());
   panPanel.add("North", upB);
   panPanel.add("East", rightB);
   panPanel.add("South", downB);
   panPanel.add("West", leftB);
   // forward, backward, and reset buttons
   Panel p = new Panel();
   p.setLayout(new GridLayout(0, 1, 0, 0));
   p.add(forwardB);
   p.add(backwardB);
   p.add(reset);
   // set the initial position
   position.x = x;
   position.y = y;
   position.z = z;
   orig_position.set(position);
   // add a mouse listener to each button
   upB.addMouseListener(this);
   downB.addMouseListener(this);
   leftB.addMouseListener(this);
   rightB.addMouseListener(this);
   forwardB.addMouseListener(this);
   backwardB.addMouseListener(this);
   reset.addMouseListener(this);
   this.setLayout(new BorderLayout());
   add("East", p);
   add("West", panPanel);
 }
 public void setDevice(InputDevice device) {
   this.device = device;
 }
 public void getPosition(Vector3f pos) {
   calculateMotion();
   pos.set(position);
 }
 public void setPosition(Vector3f pos) {
   position.set(pos);
 }
 public void setStepRate(float stepRate) {
   step_rate = stepRate;
 }
 private void calculateMotion() {
   long current_time = System.currentTimeMillis();
   long elapsed_time = current_time - time_last_state_change;
   switch (mode) {
   case STILL:
     break;
   case MOVING_LEFT:
     position.x = orig_position.x - step_rate * elapsed_time;
     break;
   case MOVING_RIGHT:
     position.x = orig_position.x + step_rate * elapsed_time;
     break;
   case MOVING_UP:
     position.y = orig_position.y + step_rate * elapsed_time;
     break;
   case MOVING_DOWN:
     position.y = orig_position.y - step_rate * elapsed_time;
     break;
   case MOVING_FORWARD:
     position.z = orig_position.z - step_rate * elapsed_time;
     break;
   case MOVING_BACK:
     position.z = orig_position.z + step_rate * elapsed_time;
     break;
   default:
     throw (new RuntimeException("Unknown motion"));
   }
 }
 public void mouseClicked(MouseEvent e) {
 }
 public void mouseEntered(MouseEvent e) {
 }
 public void mouseExited(MouseEvent e) {
 }
 public void mousePressed(MouseEvent e) {
   if (e.getSource() == leftB && mode != MOVING_LEFT) {
     time_last_state_change = System.currentTimeMillis();
     mode = MOVING_LEFT;
     orig_position.set(position);
   } else if (e.getSource() == rightB && mode != MOVING_RIGHT) {
     time_last_state_change = System.currentTimeMillis();
     mode = MOVING_RIGHT;
     orig_position.set(position);
   } else if (e.getSource() == upB && mode != MOVING_UP) {
     time_last_state_change = System.currentTimeMillis();
     mode = MOVING_UP;
     orig_position.set(position);
   } else if (e.getSource() == downB && mode != MOVING_DOWN) {
     time_last_state_change = System.currentTimeMillis();
     mode = MOVING_DOWN;
     orig_position.set(position);
   } else if (e.getSource() == forwardB && mode != MOVING_FORWARD) {
     time_last_state_change = System.currentTimeMillis();
     mode = MOVING_FORWARD;
     orig_position.set(position);
   } else if (e.getSource() == backwardB && mode != MOVING_BACK) {
     time_last_state_change = System.currentTimeMillis();
     mode = MOVING_BACK;
     orig_position.set(position);
   } else if (e.getSource() == reset) {
     device.setNominalPositionAndOrientation();
   }
 }
 public void mouseReleased(MouseEvent e) {
   mode = STILL;
 }

}


      </source>