Java/3D/Texture

Материал из Java эксперт
Версия от 09:15, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Create geometry to display the texture image mapped onto a triangulated polygon

   <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.GraphicsConfigTemplate; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileReader; 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.Interpolator; import javax.media.j3d.Locale; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.PolygonAttributes; import javax.media.j3d.RotPosPathInterpolator; 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.AxisAngle4f; import javax.vecmath.Color3f; import javax.vecmath.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Quat4f; import javax.vecmath.Vector3d; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.GeometryInfo; import com.sun.j3d.utils.geometry.NormalGenerator; import com.sun.j3d.utils.geometry.Triangulator; import com.sun.j3d.utils.image.TextureLoader; /**

* This example reads in the name of a texture image and texture coordinates
* from a file and creates geometry to display the texture image mapped onto a
* triangulated polygon.
*/

public class TextureTest extends Java3dApplet {

 private static int m_kWidth = 600;
 private static int m_kHeight = 600;
 public TextureTest() {
   initJava3d();
 }
 protected int getCanvas3dWidth(Canvas3D c3d) {
   return m_kWidth - 5;
 }
 protected int getCanvas3dHeight(Canvas3D c3d) {
   return m_kHeight - 5;
 }
 protected BranchGroup createSceneBranchGroup() {
   BranchGroup objRoot = super.createSceneBranchGroup();
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
   // add an Interpolator to rotate the scene
   objTrans.addChild(createInterpolator(objTrans));
   // process the texture input files and add the geometry
   objTrans.addChild(createTextureGroup("ann.txt", -5, -5, -3, false));
   objTrans.addChild(createTextureGroup("daniel.txt", -5, 5, 3, false));
   objTrans.addChild(createTextureGroup("ann.txt", 5, 5, 3, false));
   objTrans.addChild(createTextureGroup("daniel.txt", 5, -5, -3, false));
   objRoot.addChild(objTrans);
   return objRoot;
 }
 // creates a TransformGroup and positions it and adds
 // the texture geometry as a child node
 protected TransformGroup createTextureGroup(String szFile, double x,
     double y, double z, boolean bWireframe) {
   TransformGroup tg = new TransformGroup();
   Transform3D t3d = new Transform3D();
   t3d.setTranslation(new Vector3d(x, y, z));
   tg.setTransform(t3d);
   Shape3D texShape = createTextureGeometry(szFile, bWireframe);
   if (texShape != null)
     tg.addChild(texShape);
   return tg;
 }
 // return a Shape3D that is a triangulated texture mapped polygon
 // based on the texture coordinates and name of texture image in the
 // input file
 protected Shape3D createTextureGeometry(String szFile, boolean bWireframe) {
   // load all the texture data from the file and create the geometry
   // coordinates
   TextureGeometryInfo texInfo = createTextureCoordinates(szFile);
   if (texInfo == null) {
     System.err
         .println("Could not load texture info for file:" + szFile);
     return null;
   }
   // print some stats on the loaded file
   System.out.println("Loaded File: " + szFile);
   System.out.println("   Texture image: " + texInfo.m_szImage);
   System.out.println("   Texture coordinates: "
       + texInfo.m_TexCoordArray.length);
   // create an Appearance and assign a Material
   Appearance app = new Appearance();
   PolygonAttributes polyAttribs = null;
   // create the PolygonAttributes and attach to the Appearance,
   // note that we use CULL_NONE so that the "rear" side of the geometry
   // is visible with the applied texture image
   if (bWireframe == false)
     polyAttribs = new PolygonAttributes(PolygonAttributes.POLYGON_FILL,
         PolygonAttributes.CULL_NONE, 0);
   else
     polyAttribs = new PolygonAttributes(PolygonAttributes.POLYGON_LINE,
         PolygonAttributes.CULL_NONE, 0);
   app.setPolygonAttributes(polyAttribs);
   // load the texture image and assign to the appearance
   TextureLoader texLoader = new TextureLoader(texInfo.m_szImage,
       Texture.RGB, this);
   Texture tex = texLoader.getTexture();
   app.setTexture(tex);
   // create a GeometryInfo for the QuadArray that was populated.
   GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
   gi.setCoordinates(texInfo.m_CoordArray);
   gi.setTextureCoordinates(texInfo.m_TexCoordArray);
   // use the triangulator utility to triangulate the polygon
   int[] stripCountArray = { texInfo.m_CoordArray.length };
   int[] countourCountArray = { stripCountArray.length };
   gi.setContourCounts(countourCountArray);
   gi.setStripCounts(stripCountArray);
   Triangulator triangulator = new Triangulator();
   triangulator.triangulate(gi);
   // generate normal vectors for the triangles, not
   // strictly necessary as we are not lighting the scene
   // but generally useful
   NormalGenerator normalGenerator = new NormalGenerator();
   normalGenerator.generateNormals(gi);
   // wrap the GeometryArray in a Shape3D and assign appearance
   return new Shape3D(gi.getGeometryArray(), app);
 }
 // handles the nitty-gritty details of loading the input
 // file and reading (in order):
 // - texture file image name
 // - size of the geometry in the X direction
 // - Y direction scale factor
 // - number of texture coordinates
 // - each texture coordinate (X Y)
 // This could all be easily accomplished using a scenegraph
 // loader but this simple code is included for reference.
 protected TextureGeometryInfo createTextureCoordinates(String szFile) {
   // create a simple wrapper class to package our
   // return values
   TextureGeometryInfo texInfo = new TextureGeometryInfo();
   // allocate a temporary buffer to store the input file
   StringBuffer szBufferData = new StringBuffer();
   float sizeGeometryX = 0;
   float factorY = 1;
   int nNumPoints = 0;
   Point2f boundsPoint = new Point2f();
   try {
     // attach a reader to the input file
     FileReader fileIn = new FileReader(szFile);
     int nChar = 0;
     // read the entire file into the StringBuffer
     while (true) {
       nChar = fileIn.read();
       // if we have not hit the end of file
       // add the character to the StringBuffer
       if (nChar != -1)
         szBufferData.append((char) nChar);
       else
         // EOF
         break;
     }
     // create a tokenizer to tokenize the input file at whitespace
     java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
         szBufferData.toString());
     // read the name of the texture image
     texInfo.m_szImage = tokenizer.nextToken();
     // read the size of the generated geometry in the X dimension
     sizeGeometryX = Float.parseFloat(tokenizer.nextToken());
     // read the Y scale factor
     factorY = Float.parseFloat(tokenizer.nextToken());
     // read the number of texture coordinates
     nNumPoints = Integer.parseInt(tokenizer.nextToken());
     // read each texture coordinate
     texInfo.m_TexCoordArray = new Point2f[nNumPoints];
     Point2f texPoint2f = null;
     for (int n = 0; n < nNumPoints; n++) {
       // JAVA 3D 1.2 change - the Y coordinates
       // have been flipped, so we have to subtract the Y coordinate
       // from 1
       texPoint2f = new Point2f(Float
           .parseFloat(tokenizer.nextToken()), 1.0f - Float
           .parseFloat(tokenizer.nextToken()));
       texInfo.m_TexCoordArray[n] = texPoint2f;
       // keep an eye on the extents of the texture coordinates
       // so we can automatically center the geometry
       if (n == 0 || texPoint2f.x > boundsPoint.x)
         boundsPoint.x = texPoint2f.x;
       if (n == 0 || texPoint2f.y > boundsPoint.y)
         boundsPoint.y = texPoint2f.y;
     }
   } catch (Exception e) {
     System.err.println(e.toString());
     return null;
   }
   // build the array of coordinates
   texInfo.m_CoordArray = new Point3f[nNumPoints];
   for (int n = 0; n < nNumPoints; n++) {
     // scale and center the geometry based on the texture coordinates
     texInfo.m_CoordArray[n] = new Point3f(
         sizeGeometryX
             * (texInfo.m_TexCoordArray[n].x - boundsPoint.x / 2),
         factorY
             * sizeGeometryX
             * (texInfo.m_TexCoordArray[n].y - boundsPoint.y / 2),
         0);
   }
   return texInfo;
 }
 // creates a fancy RotPosPathInterpolator to spin the scene
 // between various positions and rotations.
 protected Interpolator createInterpolator(TransformGroup objTrans) {
   Transform3D t3d = new Transform3D();
   float[] knots = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.6f, 0.8f, 0.9f, 1.0f };
   Quat4f[] quats = new Quat4f[9];
   Point3f[] positions = new Point3f[9];
   AxisAngle4f axis = new AxisAngle4f(1.0f, 0.0f, 0.0f, 0.0f);
   t3d.set(axis);
   quats[0] = new Quat4f(0.3f, 1.0f, 1.0f, 0.0f);
   quats[1] = new Quat4f(1.0f, 0.0f, 0.0f, 0.3f);
   quats[2] = new Quat4f(0.2f, 1.0f, 0.0f, 0.0f);
   quats[3] = new Quat4f(0.0f, 0.2f, 1.0f, 0.0f);
   quats[4] = new Quat4f(1.0f, 0.0f, 0.4f, 0.0f);
   quats[5] = new Quat4f(0.0f, 1.0f, 1.0f, 0.2f);
   quats[6] = new Quat4f(0.3f, 0.3f, 0.0f, 0.0f);
   quats[7] = new Quat4f(1.0f, 0.0f, 1.0f, 1.0f);
   quats[8] = quats[0];
   positions[0] = new Point3f(0.0f, 0.0f, -1.0f);
   positions[1] = new Point3f(1.0f, -2.0f, -2.0f);
   positions[2] = new Point3f(-2.0f, 2.0f, -3.0f);
   positions[3] = new Point3f(1.0f, 1.0f, -4.0f);
   positions[4] = new Point3f(-4.0f, -2.0f, -5.0f);
   positions[5] = new Point3f(2.0f, 0.3f, -6.0f);
   positions[6] = new Point3f(-4.0f, 0.5f, -7.0f);
   positions[7] = new Point3f(0.0f, -1.5f, -4.0f);
   positions[8] = positions[0];
   Alpha alpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 10000, 0, 0,
       0, 0, 0);
   RotPosPathInterpolator rotPosPath = new RotPosPathInterpolator(alpha,
       objTrans, t3d, knots, quats, positions);
   rotPosPath.setSchedulingBounds(createApplicationBounds());
   return rotPosPath;
 }
 public static void main(String[] args) {
   TextureTest textureTest = new TextureTest();
   textureTest.saveCommandLineArguments(args);
   new MainFrame(textureTest, m_kWidth, m_kHeight);
 }

} //simple container class we use to package a return value. class TextureGeometryInfo {

 public String m_szImage = null;
 public Point2f[] m_TexCoordArray = null;
 public Point3f[] m_CoordArray = null;

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

* 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>
   
  
 
  



ExTexture - illustrate use of textures

   <source lang="java">

// //CLASS //ExTexture - illustrate use of textures // //LESSON //Use Texture2D and TextureAttributes to apply a texture image //to a shape. // //AUTHOR //David R. Nadeau / San Diego Supercomputer Center // 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.Appearance; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.GeometryArray; import javax.media.j3d.Group; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Light; import javax.media.j3d.Material; import javax.media.j3d.QuadArray; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; 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.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; 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 ExTexture extends Java3DFrame {

 //--------------------------------------------------------------
 //  SCENE CONTENT
 //--------------------------------------------------------------
 //
 //  Nodes (updated via menu)
 //
 private Shape3D shape = null; // overall scene shape
 private Appearance app = null; // geometry appearance
 private Appearance dummyApp = null; // temporary appearance
 private TextureAttributes texatt = null;// texture attributes
 private TextureAttributes dummyAtt = null;// temporary texture attributes
 private Texture2D tex = null; // current texture
 //
 //  Build scene
 //
 public Group buildScene() {
   // Get the current menu choices for appearance attributes
   int textureMode = ((Integer) modes[currentMode].value).intValue();
   Color3f color = (Color3f) colors[currentColor].value;
   Color3f blendColor = (Color3f) colors[currentBlendColor].value;
   // Turn on the example headlight
   setHeadlightEnable(true);
   // Default to examine navigation
   setNavigationType(Examine);
   // Disable scene graph compilation for this example
   setCompilable(false);
   // Create the scene group
   Group scene = new Group();
   // BEGIN EXAMPLE TOPIC
   // Set up a basic material
   Material mat = new Material();
   mat.setAmbientColor(0.2f, 0.2f, 0.2f);
   mat.setDiffuseColor(1.0f, 1.0f, 1.0f);
   mat.setSpecularColor(0.0f, 0.0f, 0.0f);
   mat.setLightingEnable(true);
   // Set up the texturing attributes with an initial
   // texture mode, texture transform, and blend color
   texatt = new TextureAttributes();
   texatt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
   texatt.setTextureMode(textureMode);
   texatt.setTextureTransform(new Transform3D()); // Identity
   texatt.setTextureBlendColor(blendColor.x, blendColor.y, blendColor.z,
       0.5f);
   // Enable changing these while the node component is live
   texatt.setCapability(TextureAttributes.ALLOW_MODE_WRITE);
   texatt.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_WRITE);
   texatt.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
   // Create an appearance using these attributes
   app = new Appearance();
   app.setMaterial(mat);
   app.setTextureAttributes(texatt);
   app.setTexture(tex);
   // And enable changing these while the node component is live
   app.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
   app.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE);
   // Build a shape and enable changing its appearance
   shape = new Shape3D(buildGeometry(), app);
   shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
   // END EXAMPLE TOPIC
   // Create some dummy appearance and tex attribute node components
   // In response to menu choices, we quickly switch the shape to
   // use one of these, then diddle with the main appearance or
   // tex attribute, then switch the shape back. This effectively
   // makes the appearance or tex attributes we want to change
   // become un-live during a change. We have to do this approach
   // because some texture features have no capability bits to set
   // to allow changes while live.
   dummyApp = new Appearance();
   dummyAtt = new TextureAttributes();
   scene.addChild(shape);
   return scene;
 }
 //--------------------------------------------------------------
 //  USER INTERFACE
 //--------------------------------------------------------------
 //
 //  Main
 //
 public static void main(String[] args) {
   ExTexture ex = new ExTexture();
   ex.initialize(args);
   ex.buildUniverse();
   ex.showFrame();
 }
 //  Texture enable/disable
 private boolean textureOnOff = true;
 private CheckboxMenuItem textureOnOffMenu = null;
 //  Texture image choices
 private NameValue[] images = { new NameValue("Red bricks", "brick.jpg"),
     new NameValue("Stone bricks", "stonebrk2.jpg"),
     new NameValue("Marble", "granite07rev.jpg"),
     new NameValue("Mud", "mud01.jpg"),
     new NameValue("Wood", "flooring.jpg"),
     new NameValue("Earth", "earthmap.jpg"), };
 private CheckboxMenu imageMenu = null;
 private int currentImage = 0;
 //  Texture boundary mode choices
 private NameValue[] boundaries = {
     new NameValue("CLAMP", new Integer(Texture.CLAMP)),
     new NameValue("WRAP", new Integer(Texture.WRAP)), };
 private CheckboxMenu boundaryMenu = null;
 private int currentBoundary = 0;
 //  Texture boundary color choices
 private NameValue[] colors = { new NameValue("White", White),
     new NameValue("Gray", Gray), new NameValue("Dark Gray", DarkGray),
     new NameValue("Black", Black), new NameValue("Red", Red),
     new NameValue("Dark Red", DarkRed), new NameValue("Green", Green),
     new NameValue("Dark Green", DarkGreen),
     new NameValue("Blue", Blue), new NameValue("Dark Blue", DarkBlue), };
 private CheckboxMenu colorMenu = null;
 private int currentColor = 6;
 //  Texture filter choices
 private NameValue[] filters = {
     new NameValue("POINT", new Integer(Texture.BASE_LEVEL_POINT)),
     new NameValue("LINEAR", new Integer(Texture.BASE_LEVEL_LINEAR)), };
 private CheckboxMenu filterMenu = null;
 private int currentFilter = 0;
 // Texture attributes mode choices
 private NameValue[] modes = {
     new NameValue("BLEND", new Integer(TextureAttributes.BLEND)),
     new NameValue("DECAL", new Integer(TextureAttributes.DECAL)),
     new NameValue("MODULATE", new Integer(TextureAttributes.MODULATE)),
     new NameValue("REPLACE", new Integer(TextureAttributes.REPLACE)), };
 private CheckboxMenu modeMenu = null;
 private int currentMode = 2;
 //  Texture attributes blend color choices
 private CheckboxMenu blendColorMenu = null;
 private int currentBlendColor = 6;
 private NameValue[] xforms = { new NameValue("Identity", new Integer(0)),
     new NameValue("Scale by 2", new Integer(1)),
     new NameValue("Scale by 4", new Integer(2)),
     new NameValue("Rotate by 45 degrees", new Integer(3)),
     new NameValue("Translate by 0.25", new Integer(4)), };
 private CheckboxMenu xformMenu = null;
 private int currentXform = 0;
 private Texture2D[] textureComponents;
 //
 //  Initialize the GUI (application and applet)
 //
 public void initialize(String[] args) {
   // Initialize the window, menubar, etc.
   super.initialize(args);
   exampleFrame.setTitle("Java 3D Texture Mapping Example");
   //
   //  Add a menubar menu to change texture parameters
   //    Image -->
   //    Boundary mode -->
   //    Boundary color -->
   //    Filter mode -->
   //
   Menu m = new Menu("Texture");
   textureOnOffMenu = new CheckboxMenuItem("Texturing enabled",
       textureOnOff);
   textureOnOffMenu.addItemListener(this);
   m.add(textureOnOffMenu);
   imageMenu = new CheckboxMenu("Image", images, currentImage, this);
   m.add(imageMenu);
   boundaryMenu = new CheckboxMenu("Boundary mode", boundaries,
       currentBoundary, this);
   m.add(boundaryMenu);
   colorMenu = new CheckboxMenu("Boundary color", colors, currentColor,
       this);
   m.add(colorMenu);
   filterMenu = new CheckboxMenu("Filter mode", filters, currentFilter,
       this);
   m.add(filterMenu);
   exampleMenuBar.add(m);
   //
   //  Add a menubar menu to change texture attributes parameters
   //    Mode -->
   //    Blend color -->
   //
   m = new Menu("TextureAttributes");
   modeMenu = new CheckboxMenu("Mode", modes, currentMode, this);
   m.add(modeMenu);
   blendColorMenu = new CheckboxMenu("Blend color", colors,
       currentBlendColor, this);
   m.add(blendColorMenu);
   xformMenu = new CheckboxMenu("Transform", xforms, currentXform, this);
   m.add(xformMenu);
   exampleMenuBar.add(m);
   // Preload the texture images
   //   Use the texture loading utility to read in the texture
   //   files and process them into an ImageComponent2D
   //   for use in the Background node.
   if (debug)
     System.err.println("Loading textures...");
   textureComponents = new Texture2D[images.length];
   String value = null;
   for (int i = 0; i < images.length; i++) {
     value = (String) images[i].value;
     textureComponents[i] = loadTexture(value);
   }
   tex = textureComponents[currentImage];
 }
 //
 //  Handle checkboxes and menu choices
 //
 public void checkboxChanged(CheckboxMenu menu, int check) {
   if (menu == imageMenu) {
     // Change the texture image
     currentImage = check;
     Texture tex = textureComponents[currentImage];
     int mode = ((Integer) boundaries[currentBoundary].value).intValue();
     Color3f color = (Color3f) colors[currentColor].value;
     int filter = ((Integer) filters[currentFilter].value).intValue();
     shape.setAppearance(dummyApp);
     tex.setEnable(textureOnOff);
     tex.setBoundaryModeS(mode);
     tex.setBoundaryModeT(mode);
     tex.setBoundaryColor(color.x, color.y, color.z, 0.0f);
     tex.setMagFilter(filter);
     tex.setMinFilter(filter);
     app.setTexture(tex);
     shape.setAppearance(app);
     return;
   }
   if (menu == boundaryMenu) {
     // Change the texture boundary mode
     currentBoundary = check;
     Texture tex = textureComponents[currentImage];
     int mode = ((Integer) boundaries[currentBoundary].value).intValue();
     shape.setAppearance(dummyApp);
     tex.setBoundaryModeS(mode);
     tex.setBoundaryModeT(mode);
     app.setTexture(tex);
     shape.setAppearance(app);
     return;
   }
   if (menu == colorMenu) {
     // Change the boundary color
     currentColor = check;
     Color3f color = (Color3f) colors[currentColor].value;
     Texture tex = textureComponents[currentImage];
     shape.setAppearance(dummyApp);
     tex.setBoundaryColor(color.x, color.y, color.z, 0.0f);
     app.setTexture(tex);
     shape.setAppearance(app);
     return;
   }
   if (menu == filterMenu) {
     // Change the filter mode
     currentFilter = check;
     int filter = ((Integer) filters[currentFilter].value).intValue();
     Texture tex = textureComponents[currentImage];
     shape.setAppearance(dummyApp);
     tex.setMagFilter(filter);
     tex.setMinFilter(filter);
     app.setTexture(tex);
     shape.setAppearance(app);
     return;
   }
   if (menu == modeMenu) {
     // Change the texture mode
     currentMode = check;
     int mode = ((Integer) modes[currentMode].value).intValue();
     app.setTextureAttributes(dummyAtt);
     texatt.setTextureMode(mode);
     app.setTextureAttributes(texatt);
     return;
   }
   if (menu == blendColorMenu) {
     // Change the boundary color
     currentBlendColor = check;
     Color3f color = (Color3f) colors[currentBlendColor].value;
     app.setTextureAttributes(dummyAtt);
     texatt.setTextureBlendColor(color.x, color.y, color.z, 0.5f);
     app.setTextureAttributes(texatt);
     return;
   }
   if (menu == xformMenu) {
     // Change the texture transform
     currentXform = check;
     Transform3D tt = new Transform3D();
     switch (currentXform) {
     default:
     case 0:
       // Identity
       texatt.setTextureTransform(tt);
       return;
     case 1:
       // Scale by 2
       tt.setScale(2.0);
       texatt.setTextureTransform(tt);
       return;
     case 2:
       // Scale by 4
       tt.setScale(4.0);
       texatt.setTextureTransform(tt);
       return;
     case 3:
       // Z rotate by 45 degrees
       tt.rotZ(Math.PI / 4.0);
       texatt.setTextureTransform(tt);
       return;
     case 4:
       // Translate by 0.25
       tt.set(new Vector3f(0.25f, 0.0f, 0.0f));
       texatt.setTextureTransform(tt);
       return;
     }
   }
   // Handle all other checkboxes
   super.checkboxChanged(menu, check);
 }
 public void itemStateChanged(ItemEvent event) {
   Object src = event.getSource();
   // Check if it is the texture on/off choice
   if (src == textureOnOffMenu) {
     textureOnOff = textureOnOffMenu.getState();
     Texture tex = textureComponents[currentImage];
     tex.setEnable(textureOnOff);
   }
   // Handle all other checkboxes
   super.itemStateChanged(event);
 }
 //--------------------------------------------------------------
 //  UTILITY METHODS
 //--------------------------------------------------------------
 //
 //  Handle loading a texture and setting up its attributes
 //
 private Texture2D loadTexture(String filename) {
   // Load the texture image file
   if (debug)
     System.err.println("Loading texture "" + filename + """);
   TextureLoader texLoader = new TextureLoader(filename, this);
   // If the image is NULL, something went wrong
   ImageComponent2D ic = texLoader.getImage();
   if (ic == null) {
     System.err.println("Cannot load texture "" + filename + """);
     return null;
   }
   // Configure a Texture2D with the image
   Texture2D t = (Texture2D) texLoader.getTexture();
   int mode = ((Integer) boundaries[currentBoundary].value).intValue();
   t.setBoundaryModeS(mode);
   t.setBoundaryModeT(mode);
   Color3f color = (Color3f) colors[currentColor].value;
   t.setBoundaryColor(color.x, color.y, color.z, 0.0f);
   int filter = ((Integer) filters[currentFilter].value).intValue();
   t.setMagFilter(filter);
   t.setMinFilter(filter);
   t.setMipMapMode(Texture.BASE_LEVEL);
   // Turn it on and allow future changes
   t.setEnable(true);
   t.setCapability(Texture.ALLOW_ENABLE_WRITE);
   return t;
 }
 //
 //  Build a cube using a QuadArray
 //
 public QuadArray buildGeometry() {
   QuadArray cube = new QuadArray(24, GeometryArray.COORDINATES
       | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2);
   cube.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
   cube.setCapability(GeometryArray.ALLOW_TEXCOORD_WRITE);
   VertexList vl = new VertexList(cube);
   float MAX = 1.0f;
   float MIN = 0.0f;
   //           Coordinate Normal Texture
   //             X Y Z I J K S T
   // Front
   vl.xyzijkst(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, MIN, MIN);
   vl.xyzijkst(1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, MAX, MIN);
   vl.xyzijkst(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, MAX, MAX);
   vl.xyzijkst(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, MIN, MAX);
   // Back
   vl.xyzijkst(1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, MAX, MIN);
   vl.xyzijkst(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, MIN, MIN);
   vl.xyzijkst(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, MIN, MAX);
   vl.xyzijkst(1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, MAX, MAX);
   // Right
   vl.xyzijkst(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, MIN, MAX);
   vl.xyzijkst(1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, MIN, MIN);
   vl.xyzijkst(1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, MAX, MIN);
   vl.xyzijkst(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, MAX, MAX);
   // Left
   vl.xyzijkst(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, MIN, MIN);
   vl.xyzijkst(-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, MIN, MAX);
   vl.xyzijkst(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, MAX, MAX);
   vl.xyzijkst(-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, MAX, MIN);
   // Top
   vl.xyzijkst(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, MIN, MAX);
   vl.xyzijkst(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, MAX, MAX);
   vl.xyzijkst(1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, MAX, MIN);
   vl.xyzijkst(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, MIN, MIN);
   // Bottom
   vl.xyzijkst(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, MIN, MIN);
   vl.xyzijkst(1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, MAX, MIN);
   vl.xyzijkst(1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, MAX, MAX);
   vl.xyzijkst(-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, MIN, MAX);
   return cube;
 }
 //
 //  Use a helper class to manage the coordinate lists
 //
 private class VertexList {
   private int index = 0;
   private GeometryArray ga = null;
   public VertexList(GeometryArray newga) {
     index = 0;
     ga = newga;
   }
   public void xyzst(float x, float y, float z, float s, float t) {
     ga.setCoordinate(index, new Point3f(x, y, z));
     ga.setTextureCoordinate(index, new Point2f(s, t));
     index++;
   }
   public void xyzijkst(float x, float y, float z, float i, float j,
       float k, float s, float t) {
     ga.setCoordinate(index, new Point3f(x, y, z));
     ga.setNormal(index, new Vector3f(i, j, k));
     ga.setTextureCoordinate(index, new Point2f(s, t));
     index++;
   }
 }

} /**

* 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>
   
  
 
  



Illustrates dynamic texture coordinate generation using the TexCoordGeneration 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.GraphicsConfigTemplate; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Panel; 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.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.Locale; import javax.media.j3d.Material; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.PositionInterpolator; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Shape3D; import javax.media.j3d.TexCoordGeneration; import javax.media.j3d.Texture; import javax.media.j3d.TextureAttributes; 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 javax.vecmath.Vector4f; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.GeometryInfo; import com.sun.j3d.utils.geometry.NormalGenerator; import com.sun.j3d.utils.image.TextureLoader; /**

* This example illustrates dynamic texture coordinate generation using the
* TexCoordGeneration class. The OBJECT_LINEAR, EYE_LINEAR and SPHERE_MAP modes
* are illustrated. The application creates a DEM landscape (from a sin/cos
* curve) and uses dynamic texture coordinate generation to map contours onto
* the landscape - either relative to its relative position (OBJECT_LINEAR) or
* absolute position (EYE_LINEAR). SPHERE_MAP maps the contours onto the
* landscape as a environment map. The "Rotate" and "Translate" buttons toggle
* two Interpolators that rotate and translate the entire scene respectivly.
*/

public class TexCoordTest extends Java3dApplet implements ActionListener {

 private static int m_kWidth = 500;
 private static int m_kHeight = 400;
 // we need to track these as we modify them inside
 // the actionPerformed method
 Appearance m_Appearance = null;
 TexCoordGeneration m_TexGen = null;
 PositionInterpolator m_PositionInterpolator = null;
 RotationInterpolator m_RotationInterpolator = null;
 public TexCoordTest() {
   initJava3d();
 }
 protected void addCanvas3D(Canvas3D c3d) {
   setLayout(new BorderLayout());
   add(c3d, BorderLayout.CENTER);
   Panel controlPanel = new Panel();
   // creates some GUI components so we can modify the
   // scene and texure coordinate generation at runtime
   Button eyeButton = new Button("EYE_LINEAR");
   eyeButton.addActionListener(this);
   controlPanel.add(eyeButton);
   Button objectButton = new Button("OBJECT_LINEAR");
   objectButton.addActionListener(this);
   controlPanel.add(objectButton);
   Button sphereButton = new Button("SPHERE_MAP");
   sphereButton.addActionListener(this);
   controlPanel.add(sphereButton);
   Button rotateButton = new Button("Rotate");
   rotateButton.addActionListener(this);
   controlPanel.add(rotateButton);
   Button translateButton = new Button("Translate");
   translateButton.addActionListener(this);
   controlPanel.add(translateButton);
   add(controlPanel, BorderLayout.SOUTH);
   doLayout();
 }
 // overidden as we don"t want a background for this example
 protected Background createBackground() {
   return null;
 }
 // we are using a big landscape so we have to scale it down
 protected double getScale() {
   return 0.05;
 }
 // handle event from the GUI components we created
 public void actionPerformed(ActionEvent event) {
   if (event.getActionCommand().equals("EYE_LINEAR") != false)
     m_TexGen.setGenMode(TexCoordGeneration.EYE_LINEAR);
   else if (event.getActionCommand().equals("OBJECT_LINEAR") != false)
     m_TexGen.setGenMode(TexCoordGeneration.OBJECT_LINEAR);
   else if (event.getActionCommand().equals("SPHERE_MAP") != false)
     m_TexGen.setGenMode(TexCoordGeneration.SPHERE_MAP);
   else if (event.getActionCommand().equals("Rotate") != false)
     m_RotationInterpolator.setEnable(!m_RotationInterpolator
         .getEnable());
   else if (event.getActionCommand().equals("Translate") != false)
     m_PositionInterpolator.setEnable(!m_PositionInterpolator
         .getEnable());
   // apply any changes to the TexCoordGeneration and copy into the
   // appearance
   TexCoordGeneration texCoordGeneration = new TexCoordGeneration();
   texCoordGeneration = (TexCoordGeneration) m_TexGen
       .cloneNodeComponent(true);
   m_Appearance.setTexCoordGeneration(texCoordGeneration);
 }
 // position the viewer in the scene
 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.rotX(0.4);
   t3d.setScale(getScale());
   t3d.setTranslation(new Vector3d(0.0, 0, -20.0));
   t3d.invert();
   tgArray[0].setTransform(t3d);
   return tgArray;
 }
 // we create a scene composed of two nested interpolators
 // one for translation, one for rotation that control
 // a DEM landscape created from a single Shape3D containing
 // a QuadArray.
 protected BranchGroup createSceneBranchGroup() {
   BranchGroup objRoot = super.createSceneBranchGroup();
   TransformGroup objPosition = new TransformGroup();
   objPosition.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   TransformGroup objRotate = new TransformGroup();
   objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   Transform3D axisTranslate = new Transform3D();
   axisTranslate.rotZ(Math.toRadians(90));
   Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
       6000, 0, 0, 0, 0, 0);
   m_PositionInterpolator = new PositionInterpolator(rotationAlpha,
       objPosition, axisTranslate, 0, 70);
   m_PositionInterpolator.setSchedulingBounds(createApplicationBounds());
   objPosition.addChild(m_PositionInterpolator);
   m_PositionInterpolator.setEnable(false);
   m_RotationInterpolator = new RotationInterpolator(rotationAlpha,
       objRotate, new Transform3D(), 0.0f, (float) Math.PI * 2.0f);
   m_RotationInterpolator.setSchedulingBounds(getApplicationBounds());
   objRotate.addChild(m_RotationInterpolator);
   m_RotationInterpolator.setEnable(true);
   TransformGroup tgLand = new TransformGroup();
   Transform3D t3dLand = new Transform3D();
   t3dLand.setTranslation(new Vector3d(0, -30, 0));
   tgLand.setTransform(t3dLand);
   tgLand.addChild(createDemLandscape());
   objRotate.addChild(tgLand);
   objPosition.addChild(objRotate);
   objRoot.addChild(objPosition);
   // create some lights for the scene
   Color3f lColor1 = new Color3f(0.3f, 0.3f, 0.3f);
   Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
   Color3f alColor = new Color3f(0.1f, 0.1f, 0.1f);
   AmbientLight aLgt = new AmbientLight(alColor);
   aLgt.setInfluencingBounds(getApplicationBounds());
   DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
   lgt1.setInfluencingBounds(getApplicationBounds());
   // add the lights to the parent BranchGroup
   objRoot.addChild(aLgt);
   objRoot.addChild(lgt1);
   return objRoot;
 }
 // create the Appearance for the landscape Shape3D
 // and initialize all the texture generation paramters
 // the yMaxHeight paramters is the maximum height of the
 // landscape. It defines a scale factor to convert from
 // landscape Y coordinates to texture coordinates
 // (in the range 0 to 1).
 void createAppearance(double yMaxHeight) {
   // create an Appearance and assign a Material
   m_Appearance = new Appearance();
   m_Appearance.setCapability(Appearance.ALLOW_TEXGEN_WRITE);
   Color3f black = new Color3f(0, 0.2f, 0);
   Color3f objColor = new Color3f(0.1f, 0.7f, 0.2f);
   m_Appearance.setMaterial(new Material(objColor, black, objColor, black,
       0.8f));
   // load the texture image
   TextureLoader texLoader = new TextureLoader("stripes.gif", Texture.RGB,
       this);
   // clamp the coordinates in the S dimension, that way they
   // will not wrap when the calculated texture coordinate falls outside
   // the range 0 to 1. When the texture coordinate is outside this range
   // no texture coordinate will be used
   Texture tex = texLoader.getTexture();
   tex.setBoundaryModeS(Texture.CLAMP);
   // assign the texute image to the appearance
   m_Appearance.setTexture(tex);
   // create the TexCoordGeneration object.
   // we are only using 1D texture coordinates (S) - texture coordinates
   // are calculated from a vertex"s distance from the Y = 0 plane
   // the 4th parameter to the Vector4f is the distance in *texture
   // coordinates*
   // that we shift the texture coordinates by (i.e. Y = 0 corresponds to S
   // = 0.5)
   TexCoordGeneration texGen = new TexCoordGeneration(
       TexCoordGeneration.OBJECT_LINEAR,
       TexCoordGeneration.TEXTURE_COORDINATE_2, new Vector4f(0,
           (float) (1.0 / (2 * yMaxHeight)), 0, 0.5f),
       new Vector4f(0, 0, 0, 0), new Vector4f(0, 0, 0, 0));
   // create our "non-live" TexCoordGeneration object so we
   // can update the "genMode" parameter after we go live.
   m_TexGen = (TexCoordGeneration) texGen.cloneNodeComponent(true);
   // assign the TexCoordGeneration to the Appearance
   m_Appearance.setTexCoordGeneration(texGen);
   // we just glue the texture image to the surface, we are not
   // blending or modulating the texture image based on material
   // attributes. You can experiment with MODULATE or BLEND.
   TextureAttributes texAttribs = new TextureAttributes();
   texAttribs.setTextureMode(TextureAttributes.DECAL);
   m_Appearance.setTextureAttributes(texAttribs);
 }
 // create the Shape3D and geometry for the DEM landscape
 BranchGroup createDemLandscape() {
   final double LAND_WIDTH = 200;
   final double LAND_LENGTH = 200;
   final double nTileSize = 10;
   final double yMaxHeight = LAND_WIDTH / 8;
   // calculate how many vertices we need to store all the "tiles" that
   // compose the QuadArray.
   final int nNumTiles = (int) (((LAND_LENGTH / nTileSize) * 2) * ((LAND_WIDTH / nTileSize) * 2));
   final int nVertexCount = 4 * nNumTiles;
   Point3f[] coordArray = new Point3f[nVertexCount];
   Point2f[] texCoordArray = new Point2f[nVertexCount];
   // create the Appearance for the landscape and initialize all
   // the texture coordinate generation parameters
   createAppearance(yMaxHeight);
   // create the parent BranchGroup
   BranchGroup bg = new BranchGroup();
   // create the geometry and populate a QuadArray
   // we use a simple sin/cos function to create an undulating surface
   // in the X/Z dimensions. Y dimension is the distance "above sea-level".
   int nItem = 0;
   double yValue0 = 0;
   double yValue1 = 0;
   double yValue2 = 0;
   double yValue3 = 0;
   final double xFactor = LAND_WIDTH / 5;
   final double zFactor = LAND_LENGTH / 3;
   // loop over all the tiles in the environment
   for (double x = -LAND_WIDTH; x <= LAND_WIDTH; x += nTileSize) {
     for (double z = -LAND_LENGTH; z <= LAND_LENGTH; z += nTileSize) {
       // if we are not on the last row or column create a "tile"
       // and add to the QuadArray. Use CCW winding
       if (z < LAND_LENGTH && x < LAND_WIDTH) {
         yValue0 = yMaxHeight * Math.sin(x / xFactor)
             * Math.cos(z / zFactor);
         yValue1 = yMaxHeight * Math.sin(x / xFactor)
             * Math.cos((z + nTileSize) / zFactor);
         yValue2 = yMaxHeight * Math.sin((x + nTileSize) / xFactor)
             * Math.cos((z + nTileSize) / zFactor);
         yValue3 = yMaxHeight * Math.sin((x + nTileSize) / xFactor)
             * Math.cos(z / zFactor);
         // note, we do not assign any texture coordinates!
         coordArray[nItem++] = new Point3f((float) x,
             (float) yValue0, (float) z);
         coordArray[nItem++] = new Point3f((float) x,
             (float) yValue1, (float) (z + nTileSize));
         coordArray[nItem++] = new Point3f((float) (x + nTileSize),
             (float) yValue2, (float) (z + nTileSize));
         coordArray[nItem++] = new Point3f((float) (x + nTileSize),
             (float) yValue3, (float) z);
       }
     }
   }
   // create a GeometryInfo and assign the coordinates
   GeometryInfo gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
   gi.setCoordinates(coordArray);
   // generate Normal vectors for the QuadArray that was populated.
   NormalGenerator normalGenerator = new NormalGenerator();
   normalGenerator.generateNormals(gi);
   // wrap the GeometryArray in a Shape3D
   Shape3D shape = new Shape3D(gi.getGeometryArray(), m_Appearance);
   // add the Shape3D to a BranchGroup and return
   bg.addChild(shape);
   return bg;
 }
 public static void main(String[] args) {
   TexCoordTest texCoordTest = new TexCoordTest();
   texCoordTest.saveCommandLineArguments(args);
   new MainFrame(texCoordTest, 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>
   
  
 
  



Illustrates how a texture image can be dynamically rotated at runtime

   <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.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.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.TextureAttributes; 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.behaviors.mouse.MouseBehaviorCallback; import com.sun.j3d.utils.behaviors.mouse.MouseRotate; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.image.TextureLoader; /**

* This example illustrates how a texture image can be dynamically rotated at
* runtime. A MouseRotate behavior (use the left mouse button) controls the
* rotation of the applied texture image
*/

public class TextureTransformTest extends Java3dApplet implements

   MouseBehaviorCallback {
 private static int m_kWidth = 400;
 private static int m_kHeight = 400;
 TextureAttributes m_TextureAttributes = null;
 public TextureTransformTest() {
   initJava3d();
 }
 protected double getScale() {
   return 0.08;
 }
 // create a Box with an applied Texture image and
 // a RotationInterpolator to rotate the box
 protected BranchGroup createSceneBranchGroup() {
   BranchGroup objRoot = super.createSceneBranchGroup();
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objTrans.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);
   // create the rotation interpolator to rotate the scene
   RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,
       objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f);
   rotator.setSchedulingBounds(createApplicationBounds());
   objTrans.addChild(rotator);
   // create the box
   final int nScale = 50;
   Appearance app = new Appearance();
   Box box = new Box(nScale, nScale, nScale, Primitive.GENERATE_NORMALS
       | Primitive.GENERATE_TEXTURE_COORDS, app);
   // load the texture image
   TextureLoader texLoader = new TextureLoader("texture.gif", this);
   app.setTexture(texLoader.getTexture());
   // set the texture attributes and ensure we
   // can write to the Transform for the texture attributes
   m_TextureAttributes = new TextureAttributes();
   m_TextureAttributes
       .setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
   app.setTextureAttributes(m_TextureAttributes);
   // connect all the elements
   objTrans.addChild(box);
   objRoot.addChild(objTrans);
   objRoot.addChild(createRotator());
   return objRoot;
 }
 private TransformGroup createRotator() {
   // create a ColorCube to illustrate the current rotation
   TransformGroup transTg = new TransformGroup();
   Transform3D t3d = new Transform3D();
   t3d.setTranslation(new Vector3d(-70, -70, 50));
   transTg.setTransform(t3d);
   TransformGroup subTg = new TransformGroup();
   subTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   subTg.addChild(new ColorCube(10.0));
   // attach a MouseRotate behavior so we can
   // rotate the color cube with the left mouse button
   MouseRotate mouseRot = new MouseRotate(subTg);
   subTg.addChild(mouseRot);
   // assign a transformChanged callback as we want to be
   // notified whenever the rotation of the ColorCube
   // changed ("this" implements MouseBehaviorCallback );
   mouseRot.setupCallback(this);
   mouseRot.setSchedulingBounds(getApplicationBounds());
   transTg.addChild(subTg);
   return transTg;
 }
 // this is a callback method that the MouseRotate behavior
 // calls when its Transform3D has been modified (by the user)
 public void transformChanged(int type, Transform3D transform) {
   // update the rotation of the TextureAttributes
   m_TextureAttributes.setTextureTransform(transform);
 }
 public static void main(String[] args) {
   TextureTransformTest textureTest = new TextureTransformTest();
   textureTest.saveCommandLineArguments(args);
   new MainFrame(textureTest, 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>
   
  
 
  



Image Component By Reference

   <source lang="java">

/*

* @(#)ImageComponentByReferenceTest.java 1.14 02/10/21 13:41:45
* 
* 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.awt.Container; import java.awt.Rectangle; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ruponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; import java.util.Vector; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.Group; import javax.media.j3d.ImageComponent; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.swing.BoxLayout; import javax.swing.JApplet; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; public class ImageComponentByReferenceTest extends JApplet implements

   ActionListener {
 Shape3D s1, s2;
 TextureLoader t0, t1, t2;
 int count = 0;
 Appearance app = new Appearance();
 BranchGroup objRoot = new BranchGroup();
 TransformGroup objTrans = new TransformGroup();
 BufferedImage bImage1;
 TiledImage checkBoard;
 boolean yUp = false;
 boolean byRef = true;
 JComboBox rasterType, texType;
 ImageComponent2D[] image = new ImageComponent2D[8];
 Appearance dummyApp = new Appearance();
 Texture2D texOne, texCheckBoard;
 javax.media.j3d.Raster raster;
 Box textureCube;
 Shape3D boxShape;
 int w1 = 64, h1 = 32, checkw = 16, checkh = 16;
 private java.net.URL texImage = null;
 private SimpleUniverse u = null;
 public BranchGroup createSceneGraph() {
   objRoot = new BranchGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objTrans.setCapability(Group.ALLOW_CHILDREN_WRITE);
   objRoot.addChild(objTrans);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   app.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
   textureCube = new Box(0.4f, 0.4f, 0.4f, Box.GENERATE_TEXTURE_COORDS
       | Box.GENERATE_NORMALS, app);
   boxShape = textureCube.getShape(Box.FRONT);
   boxShape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
   objTrans.addChild(textureCube);
   checkBoard = new TiledImage();
   TextureLoader texLoader = new TextureLoader(texImage, this);
   ImageComponent2D oneImage = texLoader.getImage();
   bImage1 = oneImage.getImage();
   int index = 0;
   image[index++] = new ImageComponent2D(oneImage.getFormat(),
       (RenderedImage) bImage1, false, true);
   image[index++] = new ImageComponent2D(oneImage.getFormat(),
       (RenderedImage) bImage1, true, true);
   image[index++] = new ImageComponent2D(oneImage.getFormat(),
       (RenderedImage) bImage1, false, false);
   image[index++] = new ImageComponent2D(oneImage.getFormat(),
       (RenderedImage) bImage1, true, false);
   createRaster(objRoot);
   image[index++] = new ImageComponent2D(ImageComponent.FORMAT_RGBA,
       checkBoard, false, true);
   image[index++] = new ImageComponent2D(ImageComponent.FORMAT_RGBA,
       checkBoard, true, true);
   image[index++] = new ImageComponent2D(ImageComponent.FORMAT_RGBA,
       checkBoard, false, false);
   image[index++] = new ImageComponent2D(ImageComponent.FORMAT_RGBA,
       checkBoard, true, false);
   texOne = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA, image[2]
       .getWidth(), image[2].getHeight());
   texOne.setCapability(Texture.ALLOW_IMAGE_WRITE);
   texOne.setImage(0, image[2]);
   app.setTexture(texOne);
   texCheckBoard = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
       image[4].getWidth(), image[4].getHeight());
   texCheckBoard.setCapability(Texture.ALLOW_IMAGE_WRITE);
   objRoot.rupile();
   return objRoot;
 }
 public void actionPerformed(ActionEvent e) {
   Object target = e.getSource();
   if (target == rasterType) {
     if (rasterType.getSelectedIndex() < 4) {
       raster.setSize(w1, h1);
     } else {
       raster.setSize(checkw, checkh);
     }
     raster.setImage(image[rasterType.getSelectedIndex()]);
   } else if (target == texType) {
     boxShape.setAppearance(dummyApp);
     if (texType.getSelectedIndex() < 4) {
       texOne.setImage(0, image[texType.getSelectedIndex()]);
       app.setTexture(texOne);
     } else {
       texCheckBoard.setImage(0, image[texType.getSelectedIndex()]);
       app.setTexture(texCheckBoard);
     }
     boxShape.setAppearance(app);
   }
 }
 JPanel createImagePanel() {
   JPanel panel = new JPanel();
   String texVals[] = { "One_Yup_ByCopy", "One_Yup_ByReference",
       "One_Ydown_ByCopy", "One_Ydown_ByReference",
       "Checkered_Yup_ByCopy", "Checkered_Yup_ByReference",
       "Checkered_Ydown_ByCopy", "Checkered_Ydown_ByReference" };
   rasterType = new JComboBox(texVals);
   rasterType.setLightWeightPopupEnabled(false);
   rasterType.addActionListener(this);
   rasterType.setSelectedIndex(2);
   panel.add(new JLabel("Raster Image"));
   panel.add(rasterType);
   texType = new JComboBox(texVals);
   texType.setLightWeightPopupEnabled(false);
   texType.addActionListener(this);
   texType.setSelectedIndex(2);
   panel.add(new JLabel("Texture Image"));
   panel.add(texType);
   return panel;
 }
 public ImageComponentByReferenceTest() {
 }
 public ImageComponentByReferenceTest(java.net.URL url) {
   texImage = url;
 }
 public void init() {
   if (texImage == null) {
     // the path to the image for an applet
     try {
       texImage = new java.net.URL(getCodeBase().toString()
           + "/one.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
   BranchGroup scene = createSceneGraph();
   u = new SimpleUniverse(c);
   u.getViewingPlatform().setNominalViewingTransform();
   u.addBranchGraph(scene);
   Container contentPane = getContentPane();
   JPanel p = new JPanel();
   BoxLayout boxlayout = new BoxLayout(p, BoxLayout.Y_AXIS);
   p.setLayout(boxlayout);
   contentPane.add("Center", c);
   contentPane.add("South", p);
   p.add(createImagePanel());
 }
 public void destroy() {
   u.cleanup();
 }
 public static void main(String[] args) {
   java.net.URL url = null;
   // the path to the image file for an application
   try {
     url = new java.net.URL("file:one.jpg");
   } catch (java.net.MalformedURLException ex) {
     System.out.println(ex.getMessage());
     System.exit(1);
   }
   new MainFrame(new ImageComponentByReferenceTest(url), 800, 700);
 }
 void createRaster(BranchGroup scene) {
   // Create raster geometries and shapes
   Vector3f trans = new Vector3f();
   Transform3D tr = new Transform3D();
   TransformGroup tg;
   // Left
   raster = new javax.media.j3d.Raster();
   raster.setCapability(javax.media.j3d.Raster.ALLOW_IMAGE_WRITE);
   raster.setCapability(javax.media.j3d.Raster.ALLOW_SIZE_WRITE);
   raster.setPosition(new Point3f(-0.9f, 0.75f, 0.0f));
   raster.setType(javax.media.j3d.Raster.RASTER_COLOR);
   raster.setOffset(0, 0);
   raster.setSize(image[2].getWidth(), image[2].getHeight());
   raster.setImage(image[2]);
   Shape3D sh = new Shape3D(raster, new Appearance());
   scene.addChild(sh);
 }

} class TiledImage extends Object implements RenderedImage {

 WritableRaster[][] tile = new WritableRaster[3][3];
 WritableRaster bigTile;
 ComponentColorModel colorModel;
 BufferedImage checkBoard;
 int minX = -2;
 int minY = -1;
 TiledImage() {
   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
   int[] nBits = { 8, 8, 8, 8 };
   int i, j, k, cc = 255;
   int[] bandOffset = new int[4];
   colorModel = new ComponentColorModel(cs, nBits, true, false,
       Transparency.OPAQUE, 0);
   // Create 9 tiles
   bandOffset[0] = 3;
   bandOffset[1] = 2;
   bandOffset[2] = 1;
   bandOffset[3] = 0;
   for (i = 0; i < 3; i++) {
     for (j = 0; j < 3; j++) {
       tile[i][j] = Raster.createInterleavedRaster(
           DataBuffer.TYPE_BYTE, 8, 8, 32, 4, bandOffset, null);
     }
   }
   // tile {-2, -1}
   byte[] byteData = ((DataBufferByte) tile[0][0].getDataBuffer())
       .getData();
   for (i = 4, k = 8 * 4 * 4 + 4 * 4; i < 8; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) cc;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   // tile {-1, -1}
   byteData = ((DataBufferByte) tile[1][0].getDataBuffer()).getData();
   for (i = 4, k = 8 * 4 * 4; i < 8; i++) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) cc;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   // tile {1, -1}
   byteData = ((DataBufferByte) tile[2][0].getDataBuffer()).getData();
   for (i = 4, k = 8 * 4 * 4; i < 8; i++, k += 16) {
     for (j = 0; j < 4; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   // tile {-2, 0}
   byteData = ((DataBufferByte) tile[0][1].getDataBuffer()).getData();
   for (i = 0, k = 16; i < 4; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) cc;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   for (i = 4, k = 8 * 4 * 4 + 16; i < 8; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) 0;
     }
   }
   // tile {-1, 0}
   byteData = ((DataBufferByte) tile[1][1].getDataBuffer()).getData();
   for (i = 0, k = 0; i < 4; i++) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) cc;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   for (i = 0, k = 8 * 4 * 4; i < 4; i++) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) 0;
     }
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) cc;
     }
   }
   // tile {0, 0}
   byteData = ((DataBufferByte) tile[2][1].getDataBuffer()).getData();
   for (i = 0, k = 0; i < 4; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   for (i = 4, k = 8 * 4 * 4; i < 8; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) cc;
     }
   }
   // tile {-2, 1}
   byteData = ((DataBufferByte) tile[0][2].getDataBuffer()).getData();
   for (i = 4, k = 16; i < 8; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) 0;
     }
   }
   // tile {-1, 1}
   byteData = ((DataBufferByte) tile[1][2].getDataBuffer()).getData();
   for (i = 0, k = 0; i < 8; i++) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) 0;
     }
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) cc;
     }
   }
   // tile {0, 1}
   byteData = ((DataBufferByte) tile[2][2].getDataBuffer()).getData();
   for (i = 4, k = 0; i < 8; i++, k += 16) {
     for (j = 4; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) cc;
     }
   }
   bigTile = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 16, 16,
       64, 4, bandOffset, null);
   ;
   byteData = ((DataBufferByte) bigTile.getDataBuffer()).getData();
   for (i = 0, k = 0; i < 8; i++) {
     for (j = 0; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) cc;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
     for (; j < 16; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) 0;
       byteData[k + 3] = (byte) cc;
     }
   }
   for (; i < 16; i++) {
     for (j = 0; j < 8; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) 0;
     }
     for (; j < 16; j++, k += 4) {
       byteData[k] = (byte) 0;
       byteData[k + 1] = (byte) 0;
       byteData[k + 2] = (byte) cc;
       byteData[k + 3] = (byte) cc;
     }
   }
   checkBoard = new BufferedImage(colorModel, bigTile, false, null);
 }
 // create four tiles {r, g, b, y}
 public WritableRaster copyData(WritableRaster raster) {
   return checkBoard.copyData(raster);
 }
 public ColorModel getColorModel() {
   return checkBoard.getColorModel();
 }
 public Raster getData() {
   return checkBoard.getData();
 }
 public Raster getData(Rectangle rect) {
   return checkBoard.getData(rect);
 }
 public int getHeight() {
   return 16;
 }
 public int getMinTileX() {
   return minX;
 }
 public int getMinTileY() {
   return minY;
 }
 public int getMinX() {
   return -8;
 }
 public int getMinY() {
   return -8;
 }
 public int getNumXTiles() {
   return 3;
 }
 public int getNumYTiles() {
   return 3;
 }
 public Object getProperty(String name) {
   return checkBoard.getProperty(name);
 }
 public String[] getPropertyNames() {
   return checkBoard.getPropertyNames();
 }
 public SampleModel getSampleModel() {
   return checkBoard.getSampleModel();
 }
 public Vector getSources() {
   return null;
 }
 public Raster getTile(int tileX, int tileY) {
   return tile[tileX - minX][tileY - minY];
 }
 public int getTileGridXOffset() {
   return 4;
 }
 public int getTileGridYOffset() {
   return -4;
 }
 public int getTileHeight() {
   return 8;
 }
 public int getTileWidth() {
   return 8;
 }
 public int getWidth() {
   return 16;
 }

}


      </source>
   
  
 
  



Interleaved Test

   <source lang="java">

/*

* @(#)InterleavedTest.java 1.13 02/10/21 13:41:02
* 
* 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.awt.Container; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; 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.IndexedTriangleArray; import javax.media.j3d.IndexedTriangleStripArray; import javax.media.j3d.Material; import javax.media.j3d.RenderingAttributes; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.TextureAttributes; import javax.media.j3d.TextureUnitState; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TransparencyAttributes; import javax.media.j3d.TriangleArray; import javax.media.j3d.TriangleStripArray; import javax.swing.BoxLayout; import javax.swing.JApplet; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.TitledBorder; import javax.vecmath.Color3f; import javax.vecmath.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewingPlatform; public class InterleavedTest extends JApplet implements ActionListener {

 RenderingAttributes ra;
 ColoringAttributes ca;
 Material mat;
 Appearance app;
 JComboBox geomType;
 JCheckBox transparency;
 JCheckBox textureBox;
 Shape3D shape;
 TransparencyAttributes transp;
 GeometryArray tetraRegular, tetraStrip, tetraIndexed, tetraIndexedStrip;
 GeometryArray[] geoArrays = new GeometryArray[4];
 // Globally used colors
 Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
 Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
 Color3f green = new Color3f(0.0f, 1.0f, 0.0f);
 Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);
 Color3f[] colors = { white, red, green, blue };
 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 Point2f t1 = new Point2f(0.0f, 0.0f);
 private static final Point2f t2 = new Point2f(0.5f, 1.0f);
 private static final Point2f t3 = new Point2f(1.0f, 0.0f);
 private static final Point2f t4 = new Point2f(1.0f, 1.0f);
 private static final Color3f c1 = new Color3f(1.0f, 0.0f, 0.0f);
 private static final Color3f c2 = new Color3f(0.0f, 1.0f, 0.0f);
 private static final Color3f c3 = new Color3f(0.0f, 1.0f, 1.0f);
 private static final Color3f c4 = new Color3f(1.0f, 1.0f, 0.0f);
 private static final float[] interleaved = { t1.x, t1.y, t1.x, t1.y, c1.x,
     c1.y, c1.z, // front face
     p1.x, p1.y, p1.z, // front face
     t2.x, t2.y, t2.x, t2.y, c2.x, c2.y, c2.z, p2.x, p2.y, p2.z, t4.x,
     t4.y, t4.x, t4.y, c4.x, c4.y, c4.z, p4.x, p4.y, p4.z,
     t1.x, t1.y, t1.x, t1.y, c1.x, c1.y, c1.z,// left, back face
     p1.x, p1.y, p1.z,// left, back face
     t4.x, t4.y, t4.x, t4.y, c4.x, c4.y, c4.z, p4.x, p4.y, p4.z, t3.x,
     t3.y, t3.x, t3.y, c3.x, c3.y, c3.z, p3.x, p3.y, p3.z,
     t2.x, t2.y, t2.x, t2.y, c2.x, c2.y, c2.z,// right, back face
     p2.x, p2.y, p2.z,// right, back face
     t3.x, t3.y, t3.x, t3.y, c3.x, c3.y, c3.z, p3.x, p3.y, p3.z, t4.x,
     t4.y, t4.x, t4.y, c4.x, c4.y, c4.z, p4.x, p4.y, p4.z,
     t1.x, t1.y, t1.x, t1.y, c1.x, c1.y, c1.z,// bottom face
     p1.x, p1.y, p1.z,// bottom face
     t3.x, t3.y, t3.x, t3.y, c3.x, c3.y, c3.z, p3.x, p3.y, p3.z, t2.x,
     t2.y, t2.x, t2.y, c2.x, c2.y, c2.z, p2.x, p2.y, p2.z, };
 private static final float[] indexedInterleaved = { t1.x, t1.y, t1.x, t1.y,
     c1.x, c1.y, c1.z, p1.x, p1.y, p1.z, t2.x, t2.y, t2.x, t2.y, c2.x,
     c2.y, c2.z, p2.x, p2.y, p2.z, t3.x, t3.y, t3.x, t3.y, c3.x, c3.y,
     c3.z, p3.x, p3.y, p3.z, t4.x, t4.y, t4.x, t4.y, c4.x, c4.y, c4.z,
     p4.x, p4.y, p4.z, };
 private static final int[] indices = { 0, 1, 3, 0, 3, 2, 1, 2, 3, 0, 2, 1 };
 private int[] stripVertexCounts = { 3, 3, 3, 3 };
 TextureUnitState textureUnitState[] = new TextureUnitState[2];
 Texture tex1;
 Texture tex2;
 private java.net.URL texImage1 = null;
 private java.net.URL texImage2 = null;
 private SimpleUniverse u;
 BranchGroup createSceneGraph() {
   BranchGroup objRoot = new BranchGroup();
   // Set up attributes to render lines
   app = new Appearance();
   app.setCapability(Appearance.ALLOW_TEXTURE_UNIT_STATE_WRITE);
   transp = new TransparencyAttributes();
   transp.setTransparency(0.5f);
   transp.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE);
   transp.setTransparencyMode(TransparencyAttributes.NONE);
   app.setTransparencyAttributes(transp);
   // load textures
   TextureAttributes texAttr1 = new TextureAttributes();
   texAttr1.setTextureMode(TextureAttributes.DECAL);
   TextureAttributes texAttr2 = new TextureAttributes();
   texAttr2.setTextureMode(TextureAttributes.MODULATE);
   TextureLoader tex = new TextureLoader(texImage1, new String("RGB"),
       this);
   if (tex == null)
     return null;
   tex1 = tex.getTexture();
   tex = new TextureLoader(texImage2, new String("RGB"), this);
   if (tex == null)
     return null;
   tex2 = tex.getTexture();
   textureUnitState[0] = new TextureUnitState(tex1, texAttr1, null);
   textureUnitState[1] = new TextureUnitState(tex2, texAttr2, null);
   tetraRegular = createGeometry(1);
   tetraStrip = createGeometry(2);
   tetraIndexed = createGeometry(3);
   tetraIndexedStrip = createGeometry(4);
   geoArrays[0] = tetraRegular;
   geoArrays[1] = tetraStrip;
   geoArrays[2] = tetraIndexed;
   geoArrays[3] = tetraIndexedStrip;
   shape = new Shape3D(tetraRegular, app);
   shape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
   Transform3D t = new Transform3D();
   // move the object upwards
   t.set(new Vector3f(0.0f, 0.3f, 0.0f));
   // rotate the shape
   Transform3D temp = new Transform3D();
   temp.rotX(Math.PI / 4.0d);
   t.mul(temp);
   temp.rotY(Math.PI / 4.0d);
   t.mul(temp);
   // Shrink the object
   t.setScale(0.6);
   TransformGroup trans = new TransformGroup(t);
   trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
   objRoot.addChild(trans);
   trans.addChild(shape);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   // 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);
   AmbientLight aLgt = new AmbientLight(alColor);
   aLgt.setInfluencingBounds(bounds);
   DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
   lgt1.setInfluencingBounds(bounds);
   objRoot.addChild(aLgt);
   objRoot.addChild(lgt1);
   // Let Java 3D perform optimizations on this scene graph.
   objRoot.rupile();
   return objRoot;
 }
 JPanel createGeometryByReferencePanel() {
   JPanel panel = new JPanel();
   panel.setBorder(new TitledBorder("Geometry Type"));
   String values[] = { "Array", "Strip", "Indexed", "IndexedStrip" };
   geomType = new JComboBox(values);
   geomType.setLightWeightPopupEnabled(false);
   geomType.addActionListener(this);
   geomType.setSelectedIndex(0);
   panel.add(new JLabel("Geometry Type"));
   panel.add(geomType);
   transparency = new JCheckBox("EnableTransparency", false);
   transparency.addActionListener(this);
   panel.add(transparency);
   textureBox = new JCheckBox("EnableTexture", false);
   textureBox.addActionListener(this);
   panel.add(textureBox);
   return panel;
 }
 public InterleavedTest() {
 }
 public InterleavedTest(java.net.URL texURL1, java.net.URL texURL2) {
   texImage1 = texURL1;
   texImage2 = texURL2;
 }
 public void init() {
   // create textures
   if (texImage1 == null) {
     // the path to the image for an applet
     try {
       texImage1 = new java.net.URL(getCodeBase().toString()
           + "/bg.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   if (texImage2 == null) {
     // the path to the image for an applet
     try {
       texImage2 = new java.net.URL(getCodeBase().toString()
           + "/one.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   Container contentPane = getContentPane();
   Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
   contentPane.add("Center", c);
   BranchGroup scene = createSceneGraph();
   // SimpleUniverse is a Convenience Utility class
   u = new SimpleUniverse(c);
   // add mouse behaviors to the viewingPlatform
   ViewingPlatform viewingPlatform = u.getViewingPlatform();
   // This will move the ViewPlatform back a bit so the
   // objects in the scene can be viewed.
   viewingPlatform.setNominalViewingTransform();
   // add Orbit behavior to the viewing platform
   OrbitBehavior orbit = new OrbitBehavior(c, OrbitBehavior.REVERSE_ALL);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   orbit.setSchedulingBounds(bounds);
   viewingPlatform.setViewPlatformBehavior(orbit);
   u.addBranchGraph(scene);
   // Create GUI
   JPanel p = new JPanel();
   BoxLayout boxlayout = new BoxLayout(p, BoxLayout.Y_AXIS);
   p.add(createGeometryByReferencePanel());
   p.setLayout(boxlayout);
   contentPane.add("South", p);
 }
 public void destroy() {
   u.cleanup();
 }
 public void actionPerformed(ActionEvent e) {
   Object target = e.getSource();
   if (target == geomType) {
     shape.setGeometry(geoArrays[geomType.getSelectedIndex()]);
   } else if (target == transparency) {
     if (transparency.isSelected()) {
       transp.setTransparencyMode(TransparencyAttributes.BLENDED);
     } else {
       transp.setTransparencyMode(TransparencyAttributes.NONE);
     }
   } else if (target == textureBox) {
     if (textureBox.isSelected()) {
       app.setTextureUnitState(textureUnitState);
     } else {
       app.setTextureUnitState(null);
     }
   }
 }
 public static void main(String[] args) {
   java.net.URL texURL1 = null;
   java.net.URL texURL2 = null;
   // the path to the image for an application
   try {
     texURL1 = new java.net.URL("file:bg.jpg");
     texURL2 = new java.net.URL("file:one.jpg");
   } catch (java.net.MalformedURLException ex) {
     System.out.println(ex.getMessage());
     System.exit(1);
   }
   Frame frame = new MainFrame(new InterleavedTest(texURL1, texURL2), 800,
       800);
 }
 public GeometryArray createGeometry(int type) {
   GeometryArray tetra = null;
   int texCoordSetMap[] = { 0, 0 };
   if (type == 1) {
     tetra = new TriangleArray(12, TriangleArray.COORDINATES
         | TriangleArray.COLOR_3 |
         /*
          * TriangleArray.NORMAL_3|
          */
         TriangleArray.TEXTURE_COORDINATE_2
         | TriangleArray.INTERLEAVED | TriangleArray.BY_REFERENCE,
         2, texCoordSetMap);
     tetra.setInterleavedVertices(interleaved);
   } else if (type == 2) {
     tetra = new TriangleStripArray(12, TriangleStripArray.COORDINATES
         | TriangleStripArray.COLOR_3 |
         /*
          * TriangleArray.NORMAL_3|
          */
         TriangleArray.TEXTURE_COORDINATE_2
         | TriangleStripArray.INTERLEAVED
         | TriangleStripArray.BY_REFERENCE, 2, texCoordSetMap,
         stripVertexCounts);
     tetra.setInterleavedVertices(interleaved);
   } else if (type == 3) { // Indexed Geometry
     tetra = new IndexedTriangleArray(4,
         IndexedTriangleArray.COORDINATES
             | IndexedTriangleArray.COLOR_3 |
             /*
              * IndexedTriangleArray.NORMAL_3|
              */
             IndexedTriangleArray.TEXTURE_COORDINATE_2
             | IndexedTriangleArray.INTERLEAVED
             | IndexedTriangleArray.BY_REFERENCE, 2,
         texCoordSetMap, 12);
     tetra.setInterleavedVertices(indexedInterleaved);
     ((IndexedTriangleArray) tetra).setCoordinateIndices(0, indices);
     ((IndexedTriangleArray) tetra).setColorIndices(0, indices);
     ((IndexedTriangleArray) tetra).setTextureCoordinateIndices(0, 0,
         indices);
     ((IndexedTriangleArray) tetra).setTextureCoordinateIndices(1, 0,
         indices);
   } else if (type == 4) { // Indexed strip geometry
     tetra = new IndexedTriangleStripArray(4,
         IndexedTriangleStripArray.COORDINATES
             | IndexedTriangleStripArray.COLOR_3 |
             /*
              * IndexedTriangleArray.NORMAL_3|
              */
             IndexedTriangleArray.TEXTURE_COORDINATE_2
             | IndexedTriangleStripArray.INTERLEAVED
             | IndexedTriangleStripArray.BY_REFERENCE, 2,
         texCoordSetMap, 12, stripVertexCounts);
     tetra.setInterleavedVertices(indexedInterleaved);
     ((IndexedTriangleStripArray) tetra)
         .setCoordinateIndices(0, indices);
     ((IndexedTriangleStripArray) tetra).setColorIndices(0, indices);
     ((IndexedTriangleStripArray) tetra).setTextureCoordinateIndices(0,
         0, indices);
     ((IndexedTriangleStripArray) tetra).setTextureCoordinateIndices(1,
         0, indices);
   } else if (type == 5) { // Interleaved array
   }
   return tetra;
 }

}


      </source>
   
  
 
  



LocalEyeApp creates a single plane with texture mapping

   <source lang="java">

/*

*      LocalEyeApp.java 1.0 99/04/12
*
* Copyright (c) 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.
*/

/*

* This program demonstrates the difference between Local Eye Lighting
* and Infinite Eye Lighting.  To see the difference, you need to
* comment out the appropriate line in the code, recompile and rerun
* the application.
*
* This version of the program is different than the one used to
* generate images for the tutorial document.  This this version
* both a directional and point light are included in the scene.
* the directional light is red, the point light is white.  The spheres
* are blue (diffuse) with white specular material.
*
* The red specular reflections are from the directional light.
* The white specular reflections are from the point light.
* The blue diffuse reflection is from the directional light.
* 
* This application (or a version of it) generated one or more
* of the images in Chapter 6 of Getting Started with the Java 3D API.
* The Java 3D Turtorial.
*
* See http://www.sun.ru/desktop/java3d/collateral for more information.
*
*/

import java.applet.Applet; import java.awt.BorderLayout; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.Material; import javax.media.j3d.PointLight; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.vecmath.Color3f; import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.universe.SimpleUniverse; /**

* LocalEyeApp creates a single plane with texture mapping.
*/

public class LocalEyeApp extends Applet {

   TransformGroup createTG(float x, float y, float z){
       Vector3f position = new Vector3f(x, y, z);
       Transform3D translate = new Transform3D();
       translate.set(position);
       TransformGroup trans1 = new TransformGroup(translate);
       return trans1;
   }
   Appearance createMatAppear(Color3f dColor, Color3f sColor, float shine) {
       Appearance appear = new Appearance();
       Material material = new Material();
       material.setDiffuseColor(dColor);
       material.setSpecularColor(sColor);
       material.setShininess(shine);
       appear.setMaterial(material);
       return appear;
   }
 public LocalEyeApp (){
   setLayout(new BorderLayout());
   Canvas3D c = new Canvas3D(null);
   add("Center", c);
   Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
   Color3f red   = new Color3f(1.0f, 0.0f, 0.0f);
   Color3f blue  = new Color3f(0.0f, 0.0f, 1.0f);

   BranchGroup scene = new BranchGroup();
   TransformGroup trans11 = createTG(-0.7f, 0.7f, -0.5f);
   scene.addChild(trans11);
   trans11.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans12 = createTG(0.0f, 0.7f, -0.5f);
   scene.addChild(trans12);
   trans12.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans13 = createTG(0.7f, 0.7f, -0.5f);
   scene.addChild(trans13);
   trans13.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans21 = createTG(-0.7f, 0.0f, -0.5f);
   scene.addChild(trans21);
   trans21.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans22 = createTG(0.0f, 0.0f, -0.5f);
   scene.addChild(trans22);
   trans22.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans23 = createTG(0.7f, 0.0f, -0.5f);
   scene.addChild(trans23);
   trans23.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans31 = createTG(-0.7f, -0.7f, -0.5f);
   scene.addChild(trans31);
   trans31.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans32 = createTG(0.0f, -0.7f, -0.5f);
   scene.addChild(trans32);
   trans32.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   TransformGroup trans33 = createTG(0.7f, -0.7f, -0.5f);
   scene.addChild(trans33);
   trans33.addChild(new Sphere(0.3f, Sphere.GENERATE_NORMALS, 60,
                   createMatAppear(blue, white, 1000.0f)));
   AmbientLight lightA = new AmbientLight();
   lightA.setInfluencingBounds(new BoundingSphere());
   scene.addChild(lightA);
   DirectionalLight lightD1 = new DirectionalLight();
   lightD1.setInfluencingBounds(new BoundingSphere());
   Vector3f direction = new Vector3f(0.0f, 0.0f, -1.0f);
   direction.normalize();
   lightD1.setDirection(direction);
   lightD1.setColor(red);
   scene.addChild(lightD1);
   PointLight lightP1 = new PointLight();
   lightP1.setInfluencingBounds(new BoundingSphere());
   Point3f position = new Point3f(0.0f, 0.0f, 1.0f);
   lightP1.setPosition(position);
   scene.addChild(lightP1);
   Background background = new Background();
   background.setApplicationBounds(new BoundingSphere());
   background.setColor(white);
   scene.addChild(background);
   SimpleUniverse u = new SimpleUniverse(c);
   // This will move the ViewPlatform back a bit so the
   // objects in the scene can be viewed.
   u.getViewingPlatform().setNominalViewingTransform();
   //Enable Local Eye Lighting
   u.getViewer().getView().setLocalEyeLightingEnable(true);
   u.addBranchGraph(scene);
 }
 
 public static void main(String argv[])
 {
   System.out.println("This scene has a red directional light and white point light.");
   System.out.println("The spheres are blue (diffuse) with white specular material.");
   System.out.println("The red specular reflections are from the directional light.");
   System.out.println("The white specular reflections are from the point light.");
   System.out.println("The blue diffuse reflection is from the point light.");
   new MainFrame(new LocalEyeApp(), 256, 256);
 }

}


      </source>
   
  
 
  



Multi Texture

   <source lang="java">

/*

* @(#)MultiTextureTest.java 1.13 02/10/21 13:57: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.Choice; import java.awt.GraphicsConfiguration; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.image.BufferedImage; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.ImageComponent; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; import javax.media.j3d.TextureUnitState; 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.applet.MainFrame; import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewingPlatform; public class MultiTextureTest extends Applet implements ItemListener {

 Choice choice;
 TextureUnitState textureUnitState[] = new TextureUnitState[2];
 Texture stoneTex;
 Texture skyTex;
 Texture lightTex;
 private java.net.URL stoneImage = null;
 private java.net.URL skyImage = null;
 private SimpleUniverse u = null;
 public Texture createLightMap() {
   int width = 128;
   int height = 128;
   BufferedImage bimage = new BufferedImage(width, height,
       BufferedImage.TYPE_INT_RGB);
   int[] rgbArray = new int[width * height];
   int index, index2;
   int rgbInc = 256 / (width / 2 - 20);
   int rgbValue = 0;
   int k = width / 2 - 5;
   int i, j, rgb;
   rgb = 0xff;
   rgbValue = rgb | (rgb << 8) | (rgb << 16) | (rgb << 24);
   for (i = width / 2 - 1, j = 0; j < 10; j++, i--) {
     rgbArray[i] = rgbValue;
   }
   for (; i > 8; i--, rgb -= rgbInc) {
     rgbValue = rgb | (rgb << 8) | (rgb << 16) | (rgb << 24);
     rgbArray[i] = rgbValue;
   }
   for (; i >= 0; i--) {
     rgbArray[i] = rgbValue;
   }
   for (i = 0; i < width / 2; i++) {
     rgbValue = rgbArray[i];
     index = i;
     index2 = (width - i - 1);
     for (j = 0; j < height; j++) {
       rgbArray[index] = rgbArray[index2] = rgbValue;
       index += width;
       index2 += width;
     }
   }
   bimage.setRGB(0, 0, width, height, rgbArray, 0, width);
   ImageComponent2D grayImage = new ImageComponent2D(
       ImageComponent.FORMAT_RGB, bimage);
   lightTex = new Texture2D(Texture.BASE_LEVEL, Texture.RGB, width, height);
   lightTex.setImage(0, grayImage);
   return lightTex;
 }
 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);
   TransformGroup objTrans = new TransformGroup();
   //write-enable for behaviors
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
   objTrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
   objScale.addChild(objTrans);
   Appearance ap = new Appearance();
   // load textures
   TextureAttributes texAttr1 = new TextureAttributes();
   texAttr1.setTextureMode(TextureAttributes.DECAL);
   TextureAttributes texAttr2 = new TextureAttributes();
   texAttr2.setTextureMode(TextureAttributes.MODULATE);
   TextureLoader tex = new TextureLoader(stoneImage, new String("RGB"),
       this);
   if (tex == null)
     return null;
   stoneTex = tex.getTexture();
   tex = new TextureLoader(skyImage, new String("RGB"), this);
   if (tex == null)
     return null;
   skyTex = tex.getTexture();
   lightTex = createLightMap();
   textureUnitState[0] = new TextureUnitState(stoneTex, texAttr1, null);
   textureUnitState[0].setCapability(TextureUnitState.ALLOW_STATE_WRITE);
   textureUnitState[1] = new TextureUnitState(lightTex, texAttr2, null);
   textureUnitState[1].setCapability(TextureUnitState.ALLOW_STATE_WRITE);
   ap.setTextureUnitState(textureUnitState);
   //Create a Box
   Box BoxObj = new Box(1.5f, 1.5f, 0.8f, Box.GENERATE_NORMALS
       | Box.GENERATE_TEXTURE_COORDS, ap, 2);
   // add it to the scene graph.
   objTrans.addChild(BoxObj);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   //Shine it with two lights.
   Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
   Color3f lColor2 = new Color3f(0.2f, 0.2f, 0.1f);
   Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
   Vector3f lDir2 = new Vector3f(0.0f, 0.0f, -1.0f);
   DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
   DirectionalLight lgt2 = new DirectionalLight(lColor2, lDir2);
   lgt1.setInfluencingBounds(bounds);
   lgt2.setInfluencingBounds(bounds);
   objScale.addChild(lgt1);
   objScale.addChild(lgt2);
   // Let Java 3D perform optimizations on this scene graph.
   objRoot.rupile();
   return objRoot;
 }
 public MultiTextureTest() {
 }
 public MultiTextureTest(java.net.URL stoneURL, java.net.URL skyURL) {
   stoneImage = stoneURL;
   skyImage = skyURL;
 }
 public void init() {
   if (stoneImage == null) {
     // the path to the image for an applet
     try {
       stoneImage = new java.net.URL(getCodeBase().toString()
           + "/stone.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   if (skyImage == null) {
     // the path to the image for an applet
     try {
       skyImage = new java.net.URL(getCodeBase().toString()
           + "/bg.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   setLayout(new BorderLayout());
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   Canvas3D c = new Canvas3D(config);
   add("Center", c);
   BranchGroup scene = createSceneGraph();
   u = new SimpleUniverse(c);
   ViewingPlatform viewingPlatform = u.getViewingPlatform();
   // This will move the ViewPlatform back a bit so the
   // objects in the scene can be viewed.
   viewingPlatform.setNominalViewingTransform();
   // add orbit behavior but disable translate
   OrbitBehavior orbit = new OrbitBehavior(c, OrbitBehavior.REVERSE_ALL
       | OrbitBehavior.DISABLE_TRANSLATE);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   orbit.setSchedulingBounds(bounds);
   viewingPlatform.setViewPlatformBehavior(orbit);
   u.addBranchGraph(scene);
   // create the gui
   choice = new Choice();
   choice.addItem("stone + light");
   choice.addItem("stone");
   choice.addItem("lightMap");
   choice.addItem("sky");
   choice.addItem("stone + sky");
   choice.addItemListener(this);
   add("North", choice);
 }
 public void destroy() {
   // Cleanup reference to Java3D
   textureUnitState = new TextureUnitState[2];
   u.cleanup();
 }
 public void itemStateChanged(ItemEvent e) {
   int index = choice.getSelectedIndex();
   switch (index) {
   case 0: /* stone + light */
     textureUnitState[0].setTexture(stoneTex);
     textureUnitState[1].setTexture(lightTex);
     break;
   case 1: /* stone */
     textureUnitState[0].setTexture(stoneTex);
     textureUnitState[1].setTexture(null);
     break;
   case 2: /* light */
     textureUnitState[0].setTexture(null);
     textureUnitState[1].setTexture(lightTex);
     break;
   case 3: /* sky */
     textureUnitState[0].setTexture(null);
     textureUnitState[1].setTexture(skyTex);
     break;
   case 4: /* stone + sky */
     textureUnitState[0].setTexture(stoneTex);
     textureUnitState[1].setTexture(skyTex);
     break;
   default: /* both */
     break;
   }
 }
 public static void main(String argv[]) {
   java.net.URL stoneURL = null;
   java.net.URL skyURL = null;
   // the path to the image for an application
   try {
     stoneURL = new java.net.URL("file:stone.jpg");
     skyURL = new java.net.URL("file:bg.jpg");
   } catch (java.net.MalformedURLException ex) {
     System.out.println(ex.getMessage());
     System.exit(1);
   }
   new MainFrame(new MultiTextureTest(stoneURL, skyURL), 750, 750);
 }

}


      </source>
   
  
 
  



TexCoordGeneration class to automatically define the texture coordinates

   <source lang="java">

/* Essential Java 3D Fast Ian Palmer Publisher: Springer-Verlag ISBN: 1-85233-394-4

  • /

import java.awt.BorderLayout; import java.awt.Button; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.IndexedQuadArray; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.Node; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.Shape3D; import javax.media.j3d.TexCoordGeneration; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; 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.AxisAngle4d; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.image.TextureLoader; /**

* This uses a TexCoordGeneration class to automatically define the texture
* coordinates.
* 
* @author I.J.Palmer
* @version 1.0
*/

public class SimpleTextureGen extends Frame implements ActionListener {

 protected Canvas3D myCanvas3D = new Canvas3D(null);
 protected Button myButton = new Button("Exit");
 /**
  * This function builds the view branch of the scene graph. It creates a
  * branch group and then creates the necessary view elements to give a
  * useful view of our content.
  * 
  * @param c
  *            Canvas3D that will display the view
  * @return BranchGroup that is the root of the view elements
  */
 protected BranchGroup buildViewBranch(Canvas3D c) {
   BranchGroup viewBranch = new BranchGroup();
   Transform3D viewXfm = new Transform3D();
   viewXfm.set(new Vector3f(0.0f, 0.0f, 10.0f));
   TransformGroup viewXfmGroup = new TransformGroup(viewXfm);
   ViewPlatform myViewPlatform = new ViewPlatform();
   PhysicalBody myBody = new PhysicalBody();
   PhysicalEnvironment myEnvironment = new PhysicalEnvironment();
   viewXfmGroup.addChild(myViewPlatform);
   viewBranch.addChild(viewXfmGroup);
   View myView = new View();
   myView.addCanvas3D(c);
   myView.attachViewPlatform(myViewPlatform);
   myView.setPhysicalBody(myBody);
   myView.setPhysicalEnvironment(myEnvironment);
   return viewBranch;
 }
 /**
  * Add some lights so that we can illuminate the scene. This adds one
  * ambient light to bring up the overall lighting level and one directional
  * shape to show the shape of the objects in the scene.
  * 
  * @param b
  *            BranchGroup that the lights are to be added to.
  */
 protected void addLights(BranchGroup b) {
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   Color3f lightColour1 = new Color3f(1.0f, 1.0f, 1.0f);
   Vector3f lightDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
   Color3f lightColour2 = new Color3f(1.0f, 1.0f, 1.0f);
   Vector3f lightDir2 = new Vector3f(0.0f, 0.0f, -1.0f);
   Color3f ambientColour = new Color3f(0.2f, 0.2f, 0.2f);
   AmbientLight ambientLight1 = new AmbientLight(ambientColour);
   ambientLight1.setInfluencingBounds(bounds);
   DirectionalLight directionalLight1 = new DirectionalLight(lightColour1,
       lightDir1);
   directionalLight1.setInfluencingBounds(bounds);
   b.addChild(ambientLight1);
   b.addChild(directionalLight1);
 }
 /**
  * This builds the content branch of our scene graph. The shape supplied as
  * a parameter is slightly tilted to reveal its 3D shape. It also uses the
  * addLights function to add some lights to the scene.
  * 
  * @param shape
  *            Node that represents the geometry for the content
  * @return BranchGroup that is the root of the content branch
  */
 protected BranchGroup buildContentBranch(Node shape) {
   BranchGroup contentBranch = new BranchGroup();
   Transform3D rotateCube = new Transform3D();
   rotateCube.set(new AxisAngle4d(1.0, 1.0, 0.0, Math.PI / 4.0));
   TransformGroup rotationGroup = new TransformGroup(rotateCube);
   contentBranch.addChild(rotationGroup);
   rotationGroup.addChild(shape);
   addLights(contentBranch);
   return contentBranch;
 }
 /**
  * This defines the appearance for the shape using a texture. It uses a
  * TextureLoader to load the texture image from an external file and a
  * TexCoordGeneration to define the texture coordinates.
  * 
  * @return Appearance that uses a texture.
  */
 protected Appearance DefineAppearance() {
   //This is used to automatically define the texture coordinates.
   //The coordinates are generated in object coordinates, but by
   //commented out the line with "OBJECT_LINEAR" and uncommenting
   //the line "EYE_LINEAR" the program will use eye coordinates.
   TexCoordGeneration textCoorder = new TexCoordGeneration(
       TexCoordGeneration.OBJECT_LINEAR,
       //TexCoordGeneration.EYE_LINEAR,
       TexCoordGeneration.TEXTURE_COORDINATE_2);
   //Load the texture from the external image file
   TextureLoader textLoad = new TextureLoader("housebrick.jpg", this);
   //Access the image from the loaded texture
   ImageComponent2D textImage = textLoad.getImage();
   //Create a two dimensional texture
   Texture2D texture = new Texture2D(Texture2D.BASE_LEVEL, Texture.RGB,
       textImage.getWidth(), textImage.getHeight());
   //Set the texture from the image loaded
   texture.setImage(0, textImage);
   //Create the appearance that will use the texture
   Appearance app = new Appearance();
   app.setTexture(texture);
   //Pass the coordinate generator to the appearance
   app.setTexCoordGeneration(textCoorder);
   //Define how the texture will be mapped onto the surface
   //by creating the appropriate texture attributes
   TextureAttributes textAttr = new TextureAttributes();
   textAttr.setTextureMode(TextureAttributes.REPLACE);
   app.setTextureAttributes(textAttr);
   app.setMaterial(new Material());
   return app;
 }
 /**
  * Build a cube from an IndexedQuadArray. This method creates the vertices
  * as a set of eight points and the normals as a set of six vectors (one for
  * each face). The data is then defined such that each vertex has a
  * different normal associated with it when it is being used for a different
  * face. The shape doesn"t have texture coordinates or nornmals defined
  * since the texture coordinate generator will define the necessary data.
  * 
  * @return Node that is the shape.
  */
 protected Node buildShape() {
   IndexedQuadArray indexedCube = new IndexedQuadArray(8,
       IndexedQuadArray.COORDINATES, 24);
   Point3f[] cubeCoordinates = { new Point3f(1.0f, 1.0f, 1.0f),
       new Point3f(-1.0f, 1.0f, 1.0f),
       new Point3f(-1.0f, -1.0f, 1.0f),
       new Point3f(1.0f, -1.0f, 1.0f), new Point3f(1.0f, 1.0f, -1.0f),
       new Point3f(-1.0f, 1.0f, -1.0f),
       new Point3f(-1.0f, -1.0f, -1.0f),
       new Point3f(1.0f, -1.0f, -1.0f) };
   int coordIndices[] = { 0, 1, 2, 3, 7, 6, 5, 4, 0, 3, 7, 4, 5, 6, 2, 1,
       0, 4, 5, 1, 6, 7, 3, 2 };
   int normalIndices[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
       4, 4, 4, 4, 5, 5, 5, 5 };
   int textIndices[] = { 0, 1, 2, 3, 3, 0, 1, 2, 1, 2, 3, 0, 1, 2, 3, 0,
       3, 0, 1, 2, 1, 2, 3, 0 };
   indexedCube.setCoordinates(0, cubeCoordinates);
   indexedCube.setCoordinateIndices(0, coordIndices);
   return new Shape3D(indexedCube, DefineAppearance());
 }
 /**
  * Handles the exit button action to quit the program.
  */
 public void actionPerformed(ActionEvent e) {
   dispose();
   System.exit(0);
 }
 public SimpleTextureGen() {
   VirtualUniverse myUniverse = new VirtualUniverse();
   Locale myLocale = new Locale(myUniverse);
   myLocale.addBranchGraph(buildViewBranch(myCanvas3D));
   myLocale.addBranchGraph(buildContentBranch(buildShape()));
   setTitle("SimpleWorld");
   setSize(400, 400);
   setLayout(new BorderLayout());
   add("Center", myCanvas3D);
   add("South", myButton);
   myButton.addActionListener(this);
   setVisible(true);
 }
 public static void main(String[] args) {
   SimpleTextureGen sw = new SimpleTextureGen();
 }

}

      </source>
   
  
 
  



Texture By Reference

   <source lang="java">

/*

* @(#)TextureByReference.java 1.14 02/10/21 14:36:22
* 
* 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.ruponent; import java.awt.Dimension; import java.awt.GraphicsConfiguration; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ruponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.util.Enumeration; import javax.media.j3d.Alpha; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.ImageComponent; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Material; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TriangleArray; import javax.media.j3d.WakeupCriterion; import javax.media.j3d.WakeupOnElapsedFrames; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.vecmath.Color3f; import javax.vecmath.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.TexCoord2f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; public class TextureByReference extends Applet implements ItemListener,

   ActionListener, ChangeListener {
 // need reference to animation behavior
 private AnimateTexturesBehavior animate;
 // need reference to tetrahedron
 private Tetrahedron tetra;
 // the gui buttons
 private JCheckBox flipB;
 private JRadioButton texByRef;
 private JRadioButton texByCopy;
 private JRadioButton geomByRef;
 private JRadioButton geomByCopy;
 private JRadioButton img4ByteABGR;
 private JRadioButton img3ByteBGR;
 private JRadioButton imgIntARGB;
 private JRadioButton imgCustomRGBA;
 private JRadioButton imgCustomRGB;
 private JRadioButton yUp;
 private JRadioButton yDown;
 private JButton animationB;
 private JSlider frameDelay;
 private SimpleUniverse universe = null;
 // image files used for the Texture animation for the applet,
 // or if no parameters are passed in for the application
 public static final String[] defaultFiles = { "animation1.gif",
     "animation2.gif", "animation3.gif",
     "animation4.gif", "animation5.gif",
     "animation6.gif", "animation7.gif",
     "animation8.gif", "animation9.gif",
     "animation10.gif" };
 private java.net.URL[] urls = null;
 public TextureByReference() {
 }
 public TextureByReference(java.net.URL[] fnamesP) {
   urls = fnamesP;
 }
 public void init() {
   if (urls == null) {
     urls = new java.net.URL[defaultFiles.length];
     for (int i = 0; i < defaultFiles.length; i++) {
       try {
         urls[i] = new java.net.URL(getCodeBase().toString()
             + defaultFiles[i]);
       } catch (java.net.MalformedURLException ex) {
         System.out.println(ex.getMessage());
         System.exit(1);
       }
     }
   }
   setLayout(new BorderLayout());
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   Canvas3D canvas = new Canvas3D(config);
   add("Center", canvas);
   // create a simple scene graph and attach it to a simple universe
   BranchGroup scene = createSceneGraph();
   universe = new SimpleUniverse(canvas);
   universe.getViewingPlatform().setNominalViewingTransform();
   universe.addBranchGraph(scene);
   // create the gui
   JPanel gui = buildGui();
   this.add("South", gui);
 }
 public void destroy() {
   universe.cleanup();
 }
 public JPanel buildGui() {
   flipB = new JCheckBox("flip image", true);
   flipB.addItemListener(this);
   javax.swing.Box flipBox = new javax.swing.Box(BoxLayout.Y_AXIS);
   flipBox.add(flipB);
   Component strut1 = flipBox
       .createVerticalStrut(flipB.getPreferredSize().height);
   Component strut2 = flipBox
       .createVerticalStrut(flipB.getPreferredSize().height);
   Component strut3 = flipBox
       .createVerticalStrut(flipB.getPreferredSize().height);
   Component strut4 = flipBox
       .createVerticalStrut(flipB.getPreferredSize().height);
   Component strut5 = flipBox
       .createVerticalStrut(flipB.getPreferredSize().height);
   flipBox.add(strut1);
   flipBox.add(strut2);
   flipBox.add(strut3);
   flipBox.add(strut4);
   flipBox.add(strut5);
   yUp = new JRadioButton("y up");
   yUp.addActionListener(this);
   yUp.setSelected(true);
   yDown = new JRadioButton("y down");
   yDown.addActionListener(this);
   ButtonGroup yGroup = new ButtonGroup();
   yGroup.add(yUp);
   yGroup.add(yDown);
   JLabel yLabel = new JLabel("Image Orientation:");
   javax.swing.Box yBox = new javax.swing.Box(BoxLayout.Y_AXIS);
   yBox.add(yLabel);
   yBox.add(yUp);
   yBox.add(yDown);
   strut1 = yBox.createVerticalStrut(yUp.getPreferredSize().height);
   strut2 = yBox.createVerticalStrut(yUp.getPreferredSize().height);
   strut3 = yBox.createVerticalStrut(yUp.getPreferredSize().height);
   yBox.add(strut1);
   yBox.add(strut2);
   yBox.add(strut3);
   texByRef = new JRadioButton("by reference");
   texByRef.addActionListener(this);
   texByRef.setSelected(true);
   texByCopy = new JRadioButton("by copy");
   texByCopy.addActionListener(this);
   ButtonGroup texGroup = new ButtonGroup();
   texGroup.add(texByRef);
   texGroup.add(texByCopy);
   JLabel texLabel = new JLabel("Texture:*");
   javax.swing.Box texBox = new javax.swing.Box(BoxLayout.Y_AXIS);
   texBox.add(texLabel);
   texBox.add(texByRef);
   texBox.add(texByCopy);
   strut1 = texBox.createVerticalStrut(texByRef.getPreferredSize().height);
   strut2 = texBox.createVerticalStrut(texByRef.getPreferredSize().height);
   strut3 = texBox.createVerticalStrut(texByRef.getPreferredSize().height);
   texBox.add(strut1);
   texBox.add(strut2);
   texBox.add(strut3);
   geomByRef = new JRadioButton("by reference");
   geomByRef.addActionListener(this);
   geomByRef.setSelected(true);
   geomByCopy = new JRadioButton("by copy");
   geomByCopy.addActionListener(this);
   ButtonGroup geomGroup = new ButtonGroup();
   geomGroup.add(geomByRef);
   geomGroup.add(geomByCopy);
   JLabel geomLabel = new JLabel("Geometry:");
   javax.swing.Box geomBox = new javax.swing.Box(BoxLayout.Y_AXIS);
   geomBox.add(geomLabel);
   geomBox.add(geomByRef);
   geomBox.add(geomByCopy);
   strut1 = geomBox
       .createVerticalStrut(geomByRef.getPreferredSize().height);
   strut2 = geomBox
       .createVerticalStrut(geomByRef.getPreferredSize().height);
   strut3 = geomBox
       .createVerticalStrut(geomByRef.getPreferredSize().height);
   geomBox.add(strut1);
   geomBox.add(strut2);
   geomBox.add(strut3);
   img4ByteABGR = new JRadioButton("TYPE_4BYTE_ABGR");
   img4ByteABGR.addActionListener(this);
   img4ByteABGR.setSelected(true);
   img3ByteBGR = new JRadioButton("TYPE_3BYTE_BGR");
   img3ByteBGR.addActionListener(this);
   imgIntARGB = new JRadioButton("TYPE_INT_ARGB");
   imgIntARGB.addActionListener(this);
   imgCustomRGBA = new JRadioButton("TYPE_CUSTOM RGBA");
   imgCustomRGBA.addActionListener(this);
   imgCustomRGB = new JRadioButton("TYPE_CUSTOM RGB");
   imgCustomRGB.addActionListener(this);
   ButtonGroup imgGroup = new ButtonGroup();
   imgGroup.add(img4ByteABGR);
   imgGroup.add(img3ByteBGR);
   imgGroup.add(imgIntARGB);
   imgGroup.add(imgCustomRGBA);
   imgGroup.add(imgCustomRGB);
   JLabel imgLabel = new JLabel("Image Type:*");
   javax.swing.Box imgBox = new javax.swing.Box(BoxLayout.Y_AXIS);
   imgBox.add(imgLabel);
   imgBox.add(img4ByteABGR);
   imgBox.add(img3ByteBGR);
   imgBox.add(imgIntARGB);
   imgBox.add(imgCustomRGBA);
   imgBox.add(imgCustomRGB);
   javax.swing.Box topBox = new javax.swing.Box(BoxLayout.X_AXIS);
   topBox.add(flipBox);
   topBox.add(texBox);
   topBox.add(geomBox);
   topBox.add(yBox);
   Component strut = topBox.createRigidArea(new Dimension(10, 10));
   topBox.add(strut);
   topBox.add(imgBox);
   frameDelay = new JSlider(0, 50, 0);
   frameDelay.addChangeListener(this);
   frameDelay.setSnapToTicks(true);
   frameDelay.setPaintTicks(true);
   frameDelay.setPaintLabels(true);
   frameDelay.setMajorTickSpacing(10);
   frameDelay.setMinorTickSpacing(1);
   frameDelay.setValue(20);
   JLabel delayL = new JLabel("frame delay");
   javax.swing.Box delayBox = new javax.swing.Box(BoxLayout.X_AXIS);
   delayBox.add(delayL);
   delayBox.add(frameDelay);
   animationB = new JButton(" stop animation ");
   animationB.addActionListener(this);
   JLabel texInfo1 = new JLabel(
       "*To use ImageComponent by reference feature, use TYPE_4BYTE_ABGR on Solaris");
   JLabel texInfo2 = new JLabel("and TYPE_3BYTE_BGR on Windows");
   JPanel buttonP = new JPanel();
   GridBagLayout gridbag = new GridBagLayout();
   GridBagConstraints c = new GridBagConstraints();
   buttonP.setLayout(gridbag);
   c.anchor = GridBagConstraints.CENTER;
   c.gridwidth = GridBagConstraints.REMAINDER;
   gridbag.setConstraints(topBox, c);
   buttonP.add(topBox);
   gridbag.setConstraints(delayBox, c);
   buttonP.add(delayBox);
   gridbag.setConstraints(animationB, c);
   buttonP.add(animationB);
   gridbag.setConstraints(texInfo1, c);
   buttonP.add(texInfo1);
   gridbag.setConstraints(texInfo2, c);
   buttonP.add(texInfo2);
   return buttonP;
 }
 public BranchGroup createSceneGraph() {
   // create the root of the branch group
   BranchGroup objRoot = new BranchGroup();
   // create the transform group node and initialize it
   // enable the TRANSFORM_WRITE capability so that it can be modified
   // at runtime. Add it to the root of the subgraph
   Transform3D rotate = new Transform3D();
   TransformGroup objTrans = new TransformGroup(rotate);
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objRoot.addChild(objTrans);
   // bounds
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   // set up some light
   Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
   Vector3f lDir1 = new Vector3f(-1.0f, -0.5f, -1.0f);
   Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);
   AmbientLight aLgt = new AmbientLight(alColor);
   aLgt.setInfluencingBounds(bounds);
   DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
   lgt1.setInfluencingBounds(bounds);
   objRoot.addChild(aLgt);
   objRoot.addChild(lgt1);
   Appearance appearance = new Appearance();
   // enable the TEXTURE_WRITE so we can modify it at runtime
   appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
   // load the first texture
   TextureLoader loader = new TextureLoader(urls[0],
       TextureLoader.BY_REFERENCE | TextureLoader.Y_UP, this);
   // get the texture from the loader
   Texture2D tex = (Texture2D) loader.getTexture();
   // get the BufferedImage to convert to TYPE_4BYTE_ABGR and flip
   // get the ImageComponent because we need it anyway
   ImageComponent2D imageComp = (ImageComponent2D) tex.getImage(0);
   BufferedImage bImage = imageComp.getImage();
   // convert the image
   bImage = ImageOps.convertImage(bImage, BufferedImage.TYPE_4BYTE_ABGR);
   // flip the image
   ImageOps.flipImage(bImage);
   imageComp.set(bImage);
   tex.setCapability(Texture.ALLOW_IMAGE_WRITE);
   tex.setBoundaryModeS(Texture.CLAMP);
   tex.setBoundaryModeT(Texture.CLAMP);
   tex.setBoundaryColor(1.0f, 1.0f, 1.0f, 1.0f);
   // set the image of the texture
   tex.setImage(0, imageComp);
   // set the texture on the appearance
   appearance.setTexture(tex);
   // set texture attributes
   TextureAttributes texAttr = new TextureAttributes();
   texAttr.setTextureMode(TextureAttributes.MODULATE);
   appearance.setTextureAttributes(texAttr);
   // set material properties
   Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
   Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
   appearance.setMaterial(new Material(white, black, white, black, 1.0f));
   // create a scale transform
   Transform3D scale = new Transform3D();
   scale.set(.6);
   TransformGroup objScale = new TransformGroup(scale);
   objTrans.addChild(objScale);
   tetra = new Tetrahedron(true);
   tetra.setAppearance(appearance);
   objScale.addChild(tetra);
   // create the behavior
   animate = new AnimateTexturesBehavior(tex, urls, appearance, this);
   animate.setSchedulingBounds(bounds);
   objTrans.addChild(animate);
   // add a rotation behavior so we can see all sides of the tetrahedron
   Transform3D yAxis = new Transform3D();
   Alpha rotorAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000,
       0, 0, 0, 0, 0);
   RotationInterpolator rotator = new RotationInterpolator(rotorAlpha,
       objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f);
   rotator.setSchedulingBounds(bounds);
   objTrans.addChild(rotator);
   // have java3d perform optimizations on this scene graph
   objRoot.rupile();
   return objRoot;
 }
 // callback for the animation button and delay text field
 public void actionPerformed(ActionEvent e) {
   Object o = e.getSource();
   // for the animation button
   if (o == animationB) {
     if (animate.getEnable()) {
       animate.setEnable(false);
       animationB.setText("start animation");
     } else {
       animate.setEnable(true);
       animationB.setText(" stop animation ");
     }
   }
   // for the texByRef button
   else if (o == texByRef && texByRef.isSelected()) {
     animate.setByReference(true);
   }
   // texByCopy button
   else if (o == texByCopy && texByCopy.isSelected()) {
     animate.setByReference(false);
   }
   // yUp button
   else if (o == yUp && yUp.isSelected()) {
     animate.setYUp(true);
   }
   // ydown button
   else if (o == yDown && yDown.isSelected()) {
     animate.setYUp(false);
   }
   //geomByRef button
   else if (o == geomByRef) {
     tetra.setByReference(true);
   }
   // geomByCopy button
   else if (o == geomByCopy) {
     tetra.setByReference(false);
   }
   // TYPE_INT_ARGB
   else if (o == imgIntARGB) {
     animate.setImageType(BufferedImage.TYPE_INT_ARGB);
   }
   // TYPE_4BYTE_ABGR
   else if (o == img4ByteABGR) {
     animate.setImageType(BufferedImage.TYPE_4BYTE_ABGR);
   }
   // TYPE_3BYTE_BGR
   else if (o == img3ByteBGR) {
     animate.setImageType(BufferedImage.TYPE_3BYTE_BGR);
   }
   // TYPE_CUSTOM RGBA
   else if (o == imgCustomRGBA) {
     animate.setImageTypeCustomRGBA();
   }
   // TYPE_CUSTOM RGB
   else if (o == imgCustomRGB) {
     animate.setImageTypeCustomRGB();
   }
 }
 // callback for the checkboxes
 public void itemStateChanged(ItemEvent e) {
   Object o = e.getSource();
   // for the flip checkbox
   if (o == flipB) {
     if (e.getStateChange() == ItemEvent.DESELECTED) {
       animate.setFlipImages(false);
     } else
       animate.setFlipImages(true);
   }
 }
 // callback for the slider
 public void stateChanged(ChangeEvent e) {
   Object o = e.getSource();
   // for the frame delay
   if (o == frameDelay) {
     animate.setFrameDelay(frameDelay.getValue());
   }
 }
 // allows TextureByReference to be run as an application as well as an
 // applet
 public static void main(String[] args) {
   java.net.URL fnames[] = null;
   if (args.length > 1) {
     fnames = new java.net.URL[args.length];
     for (int i = 0; i < args.length; i++) {
       try {
         fnames[i] = new java.net.URL("file:" + args[i]);
       } catch (java.net.MalformedURLException ex) {
         System.out.println(ex.getMessage());
       }
     }
   } else {
     fnames = new java.net.URL[TextureByReference.defaultFiles.length];
     for (int i = 0; i < TextureByReference.defaultFiles.length; i++) {
       try {
         fnames[i] = new java.net.URL("file:"
             + TextureByReference.defaultFiles[i]);
       } catch (java.net.MalformedURLException ex) {
         System.out.println(ex.getMessage());
         System.exit(1);
       }
     }
   }
   new MainFrame((new TextureByReference(fnames)), 650, 750);
 }

} class AnimateTexturesBehavior extends Behavior {

 // what image are we on
 private int current;
 private int max;
 // the images
 private ImageComponent2D[] images;
 // the target
 private Texture2D texture;
 private Appearance appearance;
 // the wakeup criterion
 private WakeupCriterion wakeupC;
 // are the images flipped?
 private boolean flip;
 // need the current type because by copy changes all images
 // to TYPE_INT_ARGB
 private int currentType;
 // for custom types
 public static final int TYPE_CUSTOM_RGBA = 0x01;
 public static final int TYPE_CUSTOM_RGB = 0x02;
 private int customType;
 // create a new AnimateTextureBehavior
 // initialize the images
 public AnimateTexturesBehavior(Texture2D texP, java.net.URL[] fnames,
     Appearance appP, TextureByReference applet) {
   int size = fnames.length;
   images = new ImageComponent2D[size];
   BufferedImage bImage;
   TextureLoader loader;
   for (int i = 0; i < size; i++) {
     loader = new TextureLoader(fnames[i], TextureLoader.BY_REFERENCE
         | TextureLoader.Y_UP, applet);
     images[i] = loader.getImage();
     bImage = images[i].getImage();
     // convert the image to TYPE_4BYTE_ABGR
     currentType = BufferedImage.TYPE_4BYTE_ABGR;
     bImage = ImageOps.convertImage(bImage, currentType);
     // flip the image
     flip = true;
     ImageOps.flipImage(bImage);
     // set the image on the ImageComponent to the new one
     images[i].set(bImage);
     images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
     images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
   }
   texture = texP;
   current = 0;
   max = size;
   wakeupC = new WakeupOnElapsedFrames(20);
   appearance = appP;
 }
 // initialize to the first image
 public void initialize() {
   texture.setImage(0, images[current]);
   if (current < max - 1)
     current++;
   else
     current = 0;
   wakeupOn(wakeupC);
 }
 // procesStimulus changes the ImageComponent of the texture
 public void processStimulus(Enumeration criteria) {
   //    ImageOps.printType(images[current].getImage());
   texture.setImage(0, images[current]);
   appearance.setTexture(texture);
   if (current < max - 1)
     current++;
   else
     current = 0;
   wakeupOn(wakeupC);
 }
 // flip the image -- useful depending on yUp
 public void setFlipImages(boolean b) {
   // double check that flipping is necessary
   if (b != flip) {
     BufferedImage bImage;
     // these are the same for all images so get info once
     int format = images[0].getFormat();
     boolean byRef = images[0].isByReference();
     boolean yUp = images[0].isYUp();
     // flip all the images
     // have to new ImageComponents because can"t set the image at
     // runtime
     for (int i = 0; i < images.length; i++) {
       bImage = images[i].getImage();
       ImageOps.flipImage(bImage);
       // if we are byRef and the bImage type does not match
       // currentType
       // we need to convert it. If we are not byRef we will
       // save converting until it is changed to byRef
       if (byRef && bImage.getType() != currentType) {
         if (currentType != BufferedImage.TYPE_CUSTOM) {
           bImage = ImageOps.convertImage(bImage, currentType);
         } else if (customType == this.TYPE_CUSTOM_RGBA) {
           bImage = ImageOps.convertToCustomRGBA(bImage);
         } else {
           bImage = ImageOps.convertToCustomRGB(bImage);
         }
       }
       images[i] = new ImageComponent2D(format, bImage, byRef, yUp);
       images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
       images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
     }
     // set flip to new value
     flip = b;
   }
 }
 // create new ImageComponents with yUp set to the parameter. yUp on
 // an ImageComponent cannot be changed at runtim
 public void setYUp(boolean b) {
   // double check that changing yUp is necessary
   if (b != images[0].isYUp()) {
     // these are the same for all images so get info once
     int format = images[0].getFormat();
     boolean byRef = images[0].isByReference();
     // reset yUp on all the images -- have to new ImageComponents
     // because
     // cannot change the value at runtime
     for (int i = 0; i < images.length; i++) {
       // if we are byRef and the bImage type does not match
       // currentType
       // we need to convert it. If we are not byRef we will
       // save converting until it is changed to byRef
       BufferedImage bImage = images[i].getImage();
       if (byRef && bImage.getType() != currentType) {
         //    bImage = ImageOps.convertImage(bImage, currentType);
         if (currentType != BufferedImage.TYPE_CUSTOM) {
           bImage = ImageOps.convertImage(bImage, currentType);
         } else if (customType == this.TYPE_CUSTOM_RGBA) {
           bImage = ImageOps.convertToCustomRGBA(bImage);
         } else {
           bImage = ImageOps.convertToCustomRGB(bImage);
         }
       }
       images[i] = new ImageComponent2D(format, bImage, byRef, b);
       images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
       images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
     }
   }
 }
 // create new ImageComponents with ByReference set by parameter.
 // by reference cannot be changed on an image component at runtime
 public void setByReference(boolean b) {
   // double check that changing is necessary
   if (b != images[0].isByReference()) {
     // these are the same for all images so get info once
     int format = images[0].getFormat();
     boolean yUp = images[0].isYUp();
     // reset yUp on all the images
     // have to new ImageComponents because cannot set value
     for (int i = 0; i < images.length; i++) {
       // if the bImage type does not match currentType and we are
       // setting
       // to byRef we need to convert it
       BufferedImage bImage = images[i].getImage();
       if (bImage.getType() != currentType && b) {
         //    bImage = ImageOps.convertImage(bImage, currentType);
         if (currentType != BufferedImage.TYPE_CUSTOM) {
           bImage = ImageOps.convertImage(bImage, currentType);
         } else if (customType == this.TYPE_CUSTOM_RGBA) {
           bImage = ImageOps.convertToCustomRGBA(bImage);
         } else {
           bImage = ImageOps.convertToCustomRGB(bImage);
         }
       }
       images[i] = new ImageComponent2D(format, bImage, b, yUp);
       images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
       images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
     }
   }
 }
 // make a new wakeup criterion object based on the new delay time
 public void setFrameDelay(int delay) {
   wakeupC = new WakeupOnElapsedFrames(delay);
 }
 //change the type of image
 public void setImageType(int newType) {
   currentType = newType;
   // only need to change the images if we are byRef otherwise will change
   // them when we chnage to byRef
   if (images[0].isByReference() == true) {
     // this information is the same for all
     int format = images[0].getFormat();
     boolean yUp = images[0].isYUp();
     boolean byRef = true;
     for (int i = 0; i < images.length; i++) {
       BufferedImage bImage = images[i].getImage();
       bImage = ImageOps.convertImage(bImage, currentType);
       images[i] = new ImageComponent2D(format, bImage, byRef, yUp);
       images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
       images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
     }
   }
 }
 public void setImageTypeCustomRGBA() {
   currentType = BufferedImage.TYPE_CUSTOM;
   customType = this.TYPE_CUSTOM_RGBA;
   // only need to change images if we are byRef otherwise will change
   // them when we change to byRef
   if (images[0].isByReference()) {
     // this information is the same for all
     int format = images[0].getFormat();
     boolean yUp = images[0].isYUp();
     boolean byRef = true;
     for (int i = 0; i < images.length; i++) {
       BufferedImage bImage = images[i].getImage();
       bImage = ImageOps.convertToCustomRGBA(bImage);
       images[i] = new ImageComponent2D(format, bImage, byRef, yUp);
       images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
       images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
     }
   }
 }
 public void setImageTypeCustomRGB() {
   currentType = BufferedImage.TYPE_CUSTOM;
   customType = this.TYPE_CUSTOM_RGB;
   // only need to change images if we are byRef otherwise will change
   // them when we change to byRef
   if (images[0].isByReference()) {
     // this information is the same for all
     int format = images[0].getFormat();
     boolean yUp = images[0].isYUp();
     boolean byRef = true;
     for (int i = 0; i < images.length; i++) {
       BufferedImage bImage = images[i].getImage();
       bImage = ImageOps.convertToCustomRGB(bImage);
       images[i] = new ImageComponent2D(format, bImage, byRef, yUp);
       images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ);
       images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ);
     }
   }
 }

} 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 Point2f texCoord[] = { new Point2f(-0.25f, 0.0f),
     new Point2f(1.25f, 0.0f), new Point2f(0.5f, 2.0f), };
 private TriangleArray geometryByRef;
 private TriangleArray geometryByCopy;
 // for geometry by reference
 private Point3f[] verticesArray = new Point3f[12];
 private TexCoord2f[] textureCoordsArray = new TexCoord2f[12];
 private Vector3f[] normalsArray = new Vector3f[12];
 // default to geometry by copy
 public Tetrahedron() {
   this(false);
 }
 // creates a tetrahedron with geometry by reference or by copy depending on
 // the byRef parameter
 public Tetrahedron(boolean byRef) {
   if (byRef) {
     createGeometryByRef();
     this.setGeometry(geometryByRef);
   } else {
     createGeometryByCopy();
     this.setGeometry(geometryByCopy);
   }
   this.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
   this.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
   setAppearance(new Appearance());
 }
 // create the geometry by reference and
 // store it in the geometryByRef variable
 public void createGeometryByRef() {
   //    System.out.println("createGeometryByRef");
   geometryByRef = new TriangleArray(12, TriangleArray.COORDINATES
       | TriangleArray.NORMALS | TriangleArray.TEXTURE_COORDINATE_2
       | TriangleArray.BY_REFERENCE);
   int i;
   // the coordinates
   for (i = 0; i < 12; i++) {
     verticesArray[i] = new Point3f(verts[i]);
   }
   geometryByRef.setCoordRef3f(verticesArray);
   //    System.out.println("coordinates set");
   //    Point3f[] temp1 = geometryByRef.getCoordRef3f();
   //    for (i = 0; i < 12; i++) {
   //       System.out.println(temp1[i]);
   //    }
   // the texture coordinates
   for (i = 0; i < 12; i++) {
     textureCoordsArray[i] = new TexCoord2f(texCoord[i % 3]);
   }
   geometryByRef.setTexCoordRef2f(0, textureCoordsArray);
   //    System.out.println("texture coords set");
   //    TexCoord2f[] temp2 = geometryByRef.getTexCoordRef2f(0);
   //    for (i = 0; i < 12; i++) {
   //      System.out.println(temp2[i]);
   //    }
   // the normals
   Vector3f normal = new Vector3f();
   Vector3f v1 = new Vector3f();
   Vector3f v2 = new Vector3f();
   Point3f[] pts = new Point3f[3];
   for (int face = 0; face < 4; face++) {
     pts[0] = new Point3f(verts[face * 3]);
     pts[1] = new Point3f(verts[face * 3 + 1]);
     pts[2] = new Point3f(verts[face * 3 + 2]);
     v1.sub(pts[1], pts[0]);
     v2.sub(pts[2], pts[0]);
     normal.cross(v1, v2);
     normal.normalize();
     for (i = 0; i < 3; i++) {
       normalsArray[face * 3 + i] = new Vector3f(normal);
     }
   }
   geometryByRef.setNormalRef3f(normalsArray);
   //    System.out.println("normals set");
   //    Vector3f[] temp3 = geometryByRef.getNormalRef3f();
   //    for (i = 0; i < 12; i++) {
   //      System.out.println(temp3[i]);
   //    }
 }
 // create the geometry by copy and store it in the geometryByCopy variable
 public void createGeometryByCopy() {
   int i;
   geometryByCopy = new TriangleArray(12, TriangleArray.COORDINATES
       | TriangleArray.NORMALS | TriangleArray.TEXTURE_COORDINATE_2);
   geometryByCopy.setCoordinates(0, verts);
   for (i = 0; i < 12; i++) {
     geometryByCopy.setTextureCoordinate(0, i, new TexCoord2f(
         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++) {
     geometryByCopy.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++) {
       geometryByCopy.setNormal((face * 3 + i), normal);
     }
   }
 }
 // set the geometry to geometryByRef or geometryByCopy depending on the
 // parameter. Create geometryByRef or geometryByCopy if necessary
 public void setByReference(boolean b) {
   //    System.out.println("Tetrahedron.setByReference " + b);
   // by reference is true
   if (b) {
     // if there is no geometryByRef, create it
     if (geometryByRef == null) {
       createGeometryByRef();
     }
     // set the geometry
     this.setGeometry(geometryByRef);
   }
   // by reference is false
   else {
     // if there is no geometryByCopy, create it
     if (geometryByCopy == null) {
       createGeometryByCopy();
     }
     // set the geometry
     this.setGeometry(geometryByCopy);
   }
 }

} //some useful, static image operations class ImageOps {

 // flip the image
 public static void flipImage(BufferedImage bImage) {
   int width = bImage.getWidth();
   int height = bImage.getHeight();
   int[] rgbArray = new int[width * height];
   bImage.getRGB(0, 0, width, height, rgbArray, 0, width);
   int[] tempArray = new int[width * height];
   int y2 = 0;
   for (int y = height - 1; y >= 0; y--) {
     for (int x = 0; x < width; x++) {
       tempArray[y2 * width + x] = rgbArray[y * width + x];
     }
     y2++;
   }
   bImage.setRGB(0, 0, width, height, tempArray, 0, width);
 }
 // convert the image to a specified BufferedImage type and return it
 public static BufferedImage convertImage(BufferedImage bImage, int type) {
   int width = bImage.getWidth();
   int height = bImage.getHeight();
   BufferedImage newImage = new BufferedImage(width, height, type);
   int[] rgbArray = new int[width * height];
   bImage.getRGB(0, 0, width, height, rgbArray, 0, width);
   newImage.setRGB(0, 0, width, height, rgbArray, 0, width);
   return newImage;
 }
 // print out some of the types of BufferedImages
 static void printType(BufferedImage bImage) {
   int type = bImage.getType();
   if (type == BufferedImage.TYPE_4BYTE_ABGR) {
     System.out.println("TYPE_4BYTE_ABGR");
   } else if (type == BufferedImage.TYPE_INT_ARGB) {
     System.out.println("TYPE_INT_ARGB");
   } else if (type == BufferedImage.TYPE_3BYTE_BGR) {
     System.out.println("TYPE_3BYTE_BGR");
   } else if (type == BufferedImage.TYPE_CUSTOM) {
     System.out.println("TYPE_CUSTOM");
   } else
     System.out.println(type);
 }
 public static BufferedImage convertToCustomRGBA(BufferedImage bImage) {
   if (bImage.getType() != BufferedImage.TYPE_INT_ARGB) {
     ImageOps.convertImage(bImage, BufferedImage.TYPE_INT_ARGB);
   }
   int width = bImage.getWidth();
   int height = bImage.getHeight();
   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
   int[] nBits = { 8, 8, 8, 8 };
   ColorModel cm = new ComponentColorModel(cs, nBits, true, false,
       Transparency.OPAQUE, 0);
   int[] bandOffset = { 0, 1, 2, 3 };
   WritableRaster newRaster = Raster.createInterleavedRaster(
       DataBuffer.TYPE_BYTE, width, height, width * 4, 4, bandOffset,
       null);
   byte[] byteData = ((DataBufferByte) newRaster.getDataBuffer())
       .getData();
   Raster origRaster = bImage.getData();
   int[] pixel = new int[4];
   int k = 0;
   for (int j = 0; j < height; j++) {
     for (int i = 0; i < width; i++) {
       pixel = origRaster.getPixel(i, j, pixel);
       byteData[k++] = (byte) (pixel[0]);
       byteData[k++] = (byte) (pixel[1]);
       byteData[k++] = (byte) (pixel[2]);
       byteData[k++] = (byte) (pixel[3]);
     }
   }
   BufferedImage newImage = new BufferedImage(cm, newRaster, false, null);
   //  if (newImage.getType() == BufferedImage.TYPE_CUSTOM) {
   //    System.out.println("Type is custom");
   //  }
   return newImage;
 }
 public static BufferedImage convertToCustomRGB(BufferedImage bImage) {
   if (bImage.getType() != BufferedImage.TYPE_INT_ARGB) {
     ImageOps.convertImage(bImage, BufferedImage.TYPE_INT_ARGB);
   }
   int width = bImage.getWidth();
   int height = bImage.getHeight();
   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
   int[] nBits = { 8, 8, 8 };
   ColorModel cm = new ComponentColorModel(cs, nBits, false, false,
       Transparency.OPAQUE, 0);
   int[] bandOffset = { 0, 1, 2 };
   WritableRaster newRaster = Raster.createInterleavedRaster(
       DataBuffer.TYPE_BYTE, width, height, width * 3, 3, bandOffset,
       null);
   byte[] byteData = ((DataBufferByte) newRaster.getDataBuffer())
       .getData();
   Raster origRaster = bImage.getData();
   int[] pixel = new int[4];
   int k = 0;
   for (int j = 0; j < height; j++) {
     for (int i = 0; i < width; i++) {
       pixel = origRaster.getPixel(i, j, pixel);
       byteData[k++] = (byte) (pixel[0]);
       byteData[k++] = (byte) (pixel[1]);
       byteData[k++] = (byte) (pixel[2]);
     }
   }
   BufferedImage newImage = new BufferedImage(cm, newRaster, false, null);
   //  if (newImage.getType() == BufferedImage.TYPE_CUSTOM) {
   //    System.out.println("Type is custom");
   //  }
   return newImage;
 }

}


      </source>
   
  
 
  



Texture Image

   <source lang="java">

/*

* @(#)TextureImage.java 1.26 02/10/21 13:57:32
* 
* 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.Texture; import javax.media.j3d.TextureAttributes; 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.Box; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; public class TextureImage extends Applet {

 private java.net.URL texImage = null;
 private SimpleUniverse u = null;
 public BranchGroup createSceneGraph() {
   // Create the root of the branch graph
   BranchGroup objRoot = new BranchGroup();
   // Create the transform group node and initialize it to the
   // identity. Enable the TRANSFORM_WRITE capability so that
   // our behavior code can modify it at runtime. Add it to the
   // root of the subgraph.
   TransformGroup objTrans = new TransformGroup();
   objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   objRoot.addChild(objTrans);
   // Create appearance object for textured cube
   Appearance app = new Appearance();
   Texture tex = new TextureLoader(texImage, this).getTexture();
   app.setTexture(tex);
   TextureAttributes texAttr = new TextureAttributes();
   texAttr.setTextureMode(TextureAttributes.MODULATE);
   app.setTextureAttributes(texAttr);
   // Create textured cube and add it to the scene graph.
   Box textureCube = new Box(0.4f, 0.4f, 0.4f,
       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);
   // Have Java 3D perform optimizations on this scene graph.
   objRoot.rupile();
   return objRoot;
 }
 public TextureImage() {
 }
 public TextureImage(java.net.URL url) {
   texImage = url;
 }
 public void init() {
   if (texImage == null) {
     // the path to the image for an applet
     try {
       texImage = new java.net.URL(getCodeBase().toString()
           + "/stone.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   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 TextureImage to be run as an application
 // as well as an applet
 //
 public static void main(String[] args) {
   java.net.URL url = null;
   if (args.length > 0) {
     try {
       url = new java.net.URL("file:" + args[0]);
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   } else {
     // the path to the image for an application
     try {
       url = new java.net.URL("file:stone.jpg");
     } catch (java.net.MalformedURLException ex) {
       System.out.println(ex.getMessage());
       System.exit(1);
     }
   }
   new MainFrame(new TextureImage(url), 256, 256);
 }

}


      </source>
   
  
 
  



Texture Mapping

   <source lang="java">

import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.net.MalformedURLException; import java.net.URL; import javax.media.j3d.Appearance; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.Texture2D; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; /**

* !Diese Klasse wurde fur das Laden uber ein JAR-Archiv und Applet welches ein
* JAR - Archiv nutzt angepasst Um das Programm als einfache Applikation uber
* einen class-File laufen zu lassen bitte auf den Code zum Einladen der Textur
* im Tutorial zuruckgreifen!
*/

public class TextureMapping extends Applet {

 /**
  * init Methoden fur die Darstellung als Applet
  */
 public void init() {
   setLayout(new BorderLayout());
   GraphicsConfiguration config = SimpleUniverse
       .getPreferredConfiguration();
   canvas3D = new Canvas3D(config);
   add("Center", canvas3D);
   BranchGroup szene = macheSzene();
   szene.rupile();
   universe = new SimpleUniverse(canvas3D);
   universe.getViewingPlatform().setNominalViewingTransform();
   universe.addBranchGraph(szene);
 }
 /**
  * Erstellt den Szenegraphen
  * 
  * @return BranchGroup
  */
 public BranchGroup macheSzene() {
   BranchGroup objWurzel = new BranchGroup();
   // Transformation, 2 Rotationen:
   Transform3D drehung = new Transform3D();
   Transform3D drehung2 = new Transform3D();
   drehung.rotX(Math.PI / 4.0d);
   drehung2.rotY(Math.PI / 5.0d);
   drehung.mul(drehung2);
   TransformGroup objDreh = new TransformGroup(drehung);
   objDreh.addChild(new Box(0.5f, 0.5f, 0.5f, Box.GENERATE_TEXTURE_COORDS,
       makeAppearance()));
   objWurzel.addChild(objDreh);
   return objWurzel;
 }
 /**
  * Wurfeldarstellung
  * 
  * @return Appearance
  */
 private Appearance makeAppearance() {
   Appearance a = new Appearance();
   TextureLoader loader = null;
   if (getCodeBase() != null)
     try {
       // Laden der Obj Datei als Applet mit jar
       loader = new TextureLoader(new URL("jar:" + getCodeBase()
           + "TextureMapping.jar!/burnstone.jpg"), null);
     } catch (MalformedURLException e) {
       e.printStackTrace();
     }
   else
     // Laden der Obj Datei mittels jar
     loader = new TextureLoader(ClassLoader
         .getSystemResource("burnstone.jpg"), null);
   Texture2D texture = (Texture2D) loader.getTexture();
   a.setTexture(texture);
   return a;
 }
 /**
  * gibt speicher frei
  */
 public void destroy() {
   universe.removeAllLocales();
 }
 public static void main(String[] args) {
   frame = new MainFrame(new TextureMapping(), 500, 500);
   frame.setTitle("Texture");
 }
 //---- Attribute -----------------------
 private SimpleUniverse universe;
 private Canvas3D canvas3D;
 private static Frame frame;

}

      </source>
   
  
 
  



Texture: picture ball

   <source lang="java">

/* The Joy of Java 3D by Greg Hopkins Copyright Copyright 2001

  • /

/* Materials make change the appearance of a whole shape, but sometimes even the shiniest objects can seem dull. By adding texture you can produce more interesting effects like marbling or wrapping a two-dimensional image around your object. The TextureLoader class enables you to load an image to use as a texture. The dimensions of your image must be powers of two, for example 128 pixels by 256. When you load the texture you can also specify how you want to use the image. For example, RGB to use the color of the image or LUMINANCE to see the image in black and white. After the texture is loaded, you can change the TextureAttributes to say whether you want the image to replace the object underneath or modulate the underlying color. You can also apply it as a decal or blend the image with the color of your choice. If you are using a simple object like a sphere then you will also have to enable texturing

by setting the "primitive flags". These can be set to Primitive.GENERATE_NORMALS + 
Primitive.GENERATE_TEXTURE_COORDS when you create the object.

In case this is starting to sound a bit complicated, here is an example. You can experiment with the texture settings in this example and compare the results. You can download the picture I used from http://www.java3d.org/Arizona.jpg or you can substitute a picture of your own.

  • /

import java.awt.Container; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.DirectionalLight; import javax.media.j3d.Material; import javax.media.j3d.Texture; import javax.media.j3d.TextureAttributes; import javax.vecmath.Color3f; import javax.vecmath.Color4f; 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; public class PictureBall {

 public PictureBall() {
   // Create the universe
   SimpleUniverse universe = new SimpleUniverse();
   // Create a structure to contain objects
   BranchGroup group = new BranchGroup();
   // Set up colors
   Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
   Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
   Color3f red = new Color3f(0.7f, .15f, .15f);
   // Set up the texture map
   TextureLoader loader = new TextureLoader("K:\\3d\\Arizona.jpg",
       "LUMINANCE", new Container());
   Texture texture = loader.getTexture();
   texture.setBoundaryModeS(Texture.WRAP);
   texture.setBoundaryModeT(Texture.WRAP);
   texture.setBoundaryColor(new Color4f(0.0f, 1.0f, 0.0f, 0.0f));
   // Set up the texture attributes
   //could be REPLACE, BLEND or DECAL instead of MODULATE
   TextureAttributes texAttr = new TextureAttributes();
   texAttr.setTextureMode(TextureAttributes.MODULATE);
   Appearance ap = new Appearance();
   ap.setTexture(texture);
   ap.setTextureAttributes(texAttr);
   //set up the material
   ap.setMaterial(new Material(red, black, red, black, 1.0f));
   // Create a ball to demonstrate textures
   int primflags = Primitive.GENERATE_NORMALS
       + Primitive.GENERATE_TEXTURE_COORDS;
   Sphere sphere = new Sphere(0.5f, primflags, ap);
   group.addChild(sphere);
   // Create lights
   Color3f light1Color = new Color3f(1f, 1f, 1f);
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
   DirectionalLight light1 = new DirectionalLight(light1Color,
       light1Direction);
   light1.setInfluencingBounds(bounds);
   group.addChild(light1);
   AmbientLight ambientLight = new AmbientLight(new Color3f(.5f, .5f, .5f));
   ambientLight.setInfluencingBounds(bounds);
   group.addChild(ambientLight);
   // look towards the ball
   universe.getViewingPlatform().setNominalViewingTransform();
   // add the group of objects to the Universe
   universe.addBranchGraph(group);
 }
 public static void main(String[] args) {
   new PictureBall();
 }

}

      </source>
   
  
 
  



The simple application of textures

   <source lang="java">

/* Essential Java 3D Fast Ian Palmer Publisher: Springer-Verlag ISBN: 1-85233-394-4

  • /

import java.awt.BorderLayout; import java.awt.Button; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.IndexedQuadArray; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.Node; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; 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.AxisAngle4d; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.TexCoord2f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.image.TextureLoader; /**

* This demonstrates the simple application of textures. Each face of a cube has
* an image mapped onto it exactly once. The image is loaded from an external
* file.
* 
* @author I.J.Palmer
* @version 1.0
*/

public class SimpleTexture extends Frame implements ActionListener {

 protected Canvas3D myCanvas3D = new Canvas3D(null);
 protected Button myButton = new Button("Exit");
 /**
  * This function builds the view branch of the scene graph. It creates a
  * branch group and then creates the necessary view elements to give a
  * useful view of our content.
  * 
  * @param c
  *            Canvas3D that will display the view
  * @return BranchGroup that is the root of the view elements
  */
 protected BranchGroup buildViewBranch(Canvas3D c) {
   BranchGroup viewBranch = new BranchGroup();
   Transform3D viewXfm = new Transform3D();
   viewXfm.set(new Vector3f(0.0f, 0.0f, 5.0f));
   TransformGroup viewXfmGroup = new TransformGroup(viewXfm);
   ViewPlatform myViewPlatform = new ViewPlatform();
   PhysicalBody myBody = new PhysicalBody();
   PhysicalEnvironment myEnvironment = new PhysicalEnvironment();
   viewXfmGroup.addChild(myViewPlatform);
   viewBranch.addChild(viewXfmGroup);
   View myView = new View();
   myView.addCanvas3D(c);
   myView.attachViewPlatform(myViewPlatform);
   myView.setPhysicalBody(myBody);
   myView.setPhysicalEnvironment(myEnvironment);
   return viewBranch;
 }
 /**
  * Add some lights so that we can illuminate the scene. This adds one
  * ambient light to bring up the overall lighting level and one directional
  * shape to show the shape of the objects in the scene.
  * 
  * @param b
  *            BranchGroup that the lights are to be added to.
  */
 protected void addLights(BranchGroup b) {
   BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
       100.0);
   Color3f lightColour1 = new Color3f(1.0f, 1.0f, 1.0f);
   Vector3f lightDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
   Color3f lightColour2 = new Color3f(1.0f, 1.0f, 1.0f);
   Vector3f lightDir2 = new Vector3f(0.0f, 0.0f, -1.0f);
   Color3f ambientColour = new Color3f(0.2f, 0.2f, 0.2f);
   AmbientLight ambientLight1 = new AmbientLight(ambientColour);
   ambientLight1.setInfluencingBounds(bounds);
   DirectionalLight directionalLight1 = new DirectionalLight(lightColour1,
       lightDir1);
   directionalLight1.setInfluencingBounds(bounds);
   b.addChild(ambientLight1);
   b.addChild(directionalLight1);
 }
 /**
  * This builds the content branch of our scene graph. The shape supplied as
  * a parameter is slightly tilted to reveal its 3D shape. It also uses the
  * addLights function to add some lights to the scene.
  * 
  * @param shape
  *            Node that represents the geometry for the content
  * @return BranchGroup that is the root of the content branch
  */
 protected BranchGroup buildContentBranch(Node shape) {
   BranchGroup contentBranch = new BranchGroup();
   Transform3D rotateCube = new Transform3D();
   rotateCube.set(new AxisAngle4d(1.0, 1.0, 0.0, Math.PI / 4.0));
   TransformGroup rotationGroup = new TransformGroup(rotateCube);
   contentBranch.addChild(rotationGroup);
   rotationGroup.addChild(shape);
   addLights(contentBranch);
   return contentBranch;
 }
 /**
  * This defines the appearance with a texture. The texture is loaded from an
  * external file.
  * 
  * @return Appearance that uses the texture.
  */
 protected Appearance DefineAppearance() {
   //Load the texture from the external image file
   TextureLoader textLoad = new TextureLoader("housebrick.jpg", this);
   //Access the image from the loaded texture
   ImageComponent2D textImage = textLoad.getImage();
   //Create a two dimensional texture
   Texture2D texture = new Texture2D(Texture2D.BASE_LEVEL, Texture.RGB,
       textImage.getWidth(), textImage.getHeight());
   //Set the texture from the image loaded
   texture.setImage(0, textImage);
   //Create the appearance that will use the texture
   Appearance app = new Appearance();
   app.setTexture(texture);
   //Define how the texture will be mapped onto the surface
   //by creating the appropriate texture attributes
   TextureAttributes textAttr = new TextureAttributes();
   textAttr.setTextureMode(TextureAttributes.REPLACE);
   app.setTextureAttributes(textAttr);
   app.setMaterial(new Material());
   return app;
 }
 /**
  * Build a cube from an IndexedQuadArray. This method creates the vertices
  * as a set of eight points and the normals as a set of six vectors (one for
  * each face). The data is then defined such that each vertex has a
  * different normal associated with it when it is being used for a different
  * face. The shape is created with texture coordinates so that when the
  * appearance is set it will use the appearance texture on the surface.
  * 
  * @return Node that is the shape.
  */
 protected Node buildShape() {
   IndexedQuadArray indexedCube = new IndexedQuadArray(8,
       IndexedQuadArray.COORDINATES | IndexedQuadArray.NORMALS
           | IndexedQuadArray.TEXTURE_COORDINATE_2, 24);
   Point3f[] cubeCoordinates = { new Point3f(1.0f, 1.0f, 1.0f),
       new Point3f(-1.0f, 1.0f, 1.0f),
       new Point3f(-1.0f, -1.0f, 1.0f),
       new Point3f(1.0f, -1.0f, 1.0f), new Point3f(1.0f, 1.0f, -1.0f),
       new Point3f(-1.0f, 1.0f, -1.0f),
       new Point3f(-1.0f, -1.0f, -1.0f),
       new Point3f(1.0f, -1.0f, -1.0f) };
   Vector3f[] normals = { new Vector3f(0.0f, 0.0f, 1.0f),
       new Vector3f(0.0f, 0.0f, -1.0f),
       new Vector3f(1.0f, 0.0f, 0.0f),
       new Vector3f(-1.0f, 0.0f, 0.0f),
       new Vector3f(0.0f, 1.0f, 0.0f), new Vector3f(0.0f, -1.0f, 0.0f) };
   //Define the texture coordinates. These are defined
   //as floating point pairs of values that are used to
   //map the corners of the texture image onto the vertices
   //of the face. We then define the indices into this
   //array of values in a similar way to that used for
   //the vertices and normals.
   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) };
   int coordIndices[] = { 0, 1, 2, 3, 7, 6, 5, 4, 0, 3, 7, 4, 5, 6, 2, 1,
       0, 4, 5, 1, 6, 7, 3, 2 };
   int normalIndices[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
       4, 4, 4, 4, 5, 5, 5, 5 };
   int textIndices[] = { 0, 1, 2, 3, 3, 0, 1, 2, 1, 2, 3, 0, 1, 2, 3, 0,
       3, 0, 1, 2, 1, 2, 3, 0 };
   indexedCube.setCoordinates(0, cubeCoordinates);
   indexedCube.setCoordinateIndices(0, coordIndices);
   indexedCube.setNormals(0, normals);
   indexedCube.setNormalIndices(0, normalIndices);
   indexedCube.setTextureCoordinates(0, 0, textCoord);
   indexedCube.setTextureCoordinateIndices(0, 0, textIndices);
   return new Shape3D(indexedCube, DefineAppearance());
 }
 /**
  * Handles the exit button action to quit the program.
  */
 public void actionPerformed(ActionEvent e) {
   dispose();
   System.exit(0);
 }
 public SimpleTexture() {
   VirtualUniverse myUniverse = new VirtualUniverse();
   Locale myLocale = new Locale(myUniverse);
   myLocale.addBranchGraph(buildViewBranch(myCanvas3D));
   myLocale.addBranchGraph(buildContentBranch(buildShape()));
   setTitle("SimpleTexture");
   setSize(400, 400);
   setLayout(new BorderLayout());
   add("Center", myCanvas3D);
   add("South", myButton);
   myButton.addActionListener(this);
   setVisible(true);
 }
 public static void main(String[] args) {
   SimpleTexture st = new SimpleTexture();
 }

}

      </source>