Java/3D/Rendering — различия между версиями

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

Текущая версия на 06:15, 1 июня 2010

Immediate mode rendering

/*
 *  @(#)PureImmediateStereo.java 1.4 02/10/21 13:53:11
 *
 * 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 java.awt.GraphicsEnvironment;
import java.util.Map;
import javax.media.j3d.Alpha;
import javax.media.j3d.Appearance;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.GraphicsContext3D;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.universe.SimpleUniverse;
/**
 * Pure immediate mode stereo example program for stereo. In pure immediate
 * mode, the renderer must be stopped on the Canvas being rendered into. In our
 * example, this is done immediately after the canvas is created. A separate
 * thread is started up to do the immediate mode rendering.
 */
public class PureImmediateStereo extends Applet implements Runnable {
  // Set this to true when the graphics card use shared z buffer
  // in stereo mode.
  public static String defaultSharedStereoZbuffer = Boolean.TRUE.toString();
  private boolean sharedStereoZbuffer;
  private boolean stereoSupport;
  private Canvas3D canvas;
  private GraphicsContext3D gc;
  private Shape3D leftConeBody, rightConeBody;
  private Shape3D leftConeCap, rightConeCap;
  private Transform3D cmt = new Transform3D();
  private Vector3f leftTrans, rightTrans;
  // One rotation (2*PI radians) every 6 seconds
  private Alpha rotAlpha = new Alpha(-1, 6000);
  private SimpleUniverse u = null;
  private double angle;
  // Compute data which is common for both
  // left and right eye
  void computeSharedData() {
    // Compute angle of rotation based on alpha value
    angle = rotAlpha.value() * 2.0 * Math.PI;
    cmt.rotY(angle);
  }
  // Render the geometry in right eye
  void renderLeft() {
    cmt.setTranslation(leftTrans);
    gc.setModelTransform(cmt);
    if (sharedStereoZbuffer) {
      // Graphics card shared same z buffer in stereo mode,
      // in this case we have to explicitly clearing both
      // frame buffers.
      gc.clear();
    }
    gc.draw(leftConeBody);
    gc.draw(leftConeCap);
  }
  // Render the geometry for right eye
  void renderRight() {
    cmt.setTranslation(rightTrans);
    gc.setModelTransform(cmt);
    if (sharedStereoZbuffer) {
      // Graphics card shared same z buffer in stereo mode,
      // in this case we have to explicitly clearing both
      // frame buffers.
      gc.clear();
    }
    gc.draw(rightConeBody);
    gc.draw(rightConeCap);
  }
  //
  // Run method for our immediate mode rendering thread.
  //
  public void run() {
    // Set up Graphics context
    gc = canvas.getGraphicsContext3D();
    // We always need to set this for PureImmediate
    // stereo mode
    gc.setBufferOverride(true);
    Color3f lightColor = new Color3f(1, 1, 1);
    Vector3f lightDir = new Vector3f(0, 0, -1);
    DirectionalLight light = new DirectionalLight(lightColor, lightDir);
    gc.addLight(light);
    Appearance redApp = new Appearance();
    Appearance greenApp = new Appearance();
    Color3f ambientColor = new Color3f(0, 0, 0);
    Color3f emissiveColor = new Color3f(0, 0, 0);
    Color3f diffuseColor = new Color3f(1, 0, 0);
    Color3f specularColor = new Color3f(1, 1, 1);
    redApp.setMaterial(new Material(ambientColor, emissiveColor,
        diffuseColor, specularColor, 5));
    diffuseColor = new Color3f(0, 1, 0);
    greenApp.setMaterial(new Material(ambientColor, emissiveColor,
        diffuseColor, specularColor, 5));
    // Set up geometry
    Cone leftCone = new Cone(0.4f, 0.6f, Primitive.GENERATE_NORMALS, redApp);
    Cone rightCone = new Cone(0.4f, 0.6f, Primitive.GENERATE_NORMALS,
        greenApp);
    leftConeBody = leftCone.getShape(Cone.BODY);
    leftConeCap = leftCone.getShape(Cone.CAP);
    rightConeBody = rightCone.getShape(Cone.BODY);
    rightConeCap = rightCone.getShape(Cone.CAP);
    leftTrans = new Vector3f(-0.6f, 0, 0);
    rightTrans = new Vector3f(0.6f, 0, 0);
    while (true) {
      // compute data which is can be used
      // for both left and right eye
      computeSharedData();
      if (stereoSupport) {
        if (!sharedStereoZbuffer) {
          gc.setStereoMode(GraphicsContext3D.STEREO_BOTH);
          // This clear both left and right buffers, we
          // must set STEREO_BOTH before it. Otherwise
          // it only clear LEFT or RIGHT buffer unless
          // this is invoke twice for each buffer.
          gc.clear();
        }
        gc.setStereoMode(GraphicsContext3D.STEREO_LEFT);
        renderLeft();
        gc.setStereoMode(GraphicsContext3D.STEREO_RIGHT);
        renderRight();
      } else {
        gc.clear();
        renderLeft();
      }
      // This swap both left and right buffers so
      // there is no need to set STEREO_BOTH before it
      canvas.swap();
      // Be polite to other threads !
      Thread.yield();
    }
  }
  public PureImmediateStereo() {
  }
  //
  // init: create the canvas, stop the renderer,
  // create the universe, and start the drawing thread.
  //
  public void init() {
    setLayout(new BorderLayout());
    // Preferred to use Stereo
    GraphicsConfigTemplate3D gct = new GraphicsConfigTemplate3D();
    gct.setStereo(GraphicsConfigTemplate3D.PREFERRED);
    GraphicsConfiguration config = GraphicsEnvironment
        .getLocalGraphicsEnvironment().getDefaultScreenDevice()
        .getBestConfiguration(gct);
    canvas = new Canvas3D(config);
    Map map = canvas.queryProperties();
    stereoSupport = canvas.getStereoAvailable();
    if (stereoSupport) {
      System.out
          .println("This machine support stereo, you should see a red cone on the left and green cone on the right.");
      // User can overide the above default behavior using
      // java3d property.
      String str = System.getProperty("j3d.sharedstereozbuffer",
          defaultSharedStereoZbuffer);
      sharedStereoZbuffer = (new Boolean(str)).booleanValue();
    } else {
      System.out
          .println("Stereo is not support, you should only see the left red cone.");
    }
    if (!canvas.getDoubleBufferAvailable()) {
      System.out.println("Double buffer is not support !");
    }
    // we must stop the Renderer in PureImmediate mode
    canvas.stopRenderer();
    add("Center", canvas);
    // Create the universe and viewing branch
    u = new SimpleUniverse(canvas);
    // This will move the ViewPlatform back a bit so the
    // objects in the scene can be viewed.
    u.getViewingPlatform().setNominalViewingTransform();
    // Start a new thread that will continuously render
    (new Thread(this)).start();
  }
  // Cleanup all Java3D threads and memory when this applet exit
  public void destroy() {
    u.cleanup();
  }
  //
  // The following allows PureImmediateStereo to be run as an application
  // as well as an applet
  //
  public static void main(String[] args) {
    new MainFrame(new PureImmediateStereo(), 512, 256);
  }
}





Mix rendering in immediate and retained mode to produce

/**********************************************************
 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.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.GraphicsContext3D;
import javax.media.j3d.Group;
import javax.media.j3d.Light;
import javax.media.j3d.Locale;
import javax.media.j3d.Material;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PointArray;
import javax.media.j3d.PointAttributes;
import javax.media.j3d.RotationInterpolator;
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.Point3f;
import javax.vecmath.Vector3d;
import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
/**
 * This example mixes rendering in immediate and retained (scenegraph) mode to
 * produce a composite rendered frame.
 */
public class MixedTest extends Java3dApplet {
  private static int m_kWidth = 400;
  private static int m_kHeight = 400;
  public MixedTest() {
    initJava3d();
  }
  protected Canvas3D createCanvas3D() {
    // overidden this method to create a custom
    // Canvas3D that will implement the Immediate Mode rendering
    GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
    gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
    GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
        .getScreenDevices();
    ImmediateCanvas3D c3d = new ImmediateCanvas3D(gd[0]
        .getBestConfiguration(gc3D));
    c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
    return (Canvas3D) c3d;
  }
  protected BranchGroup createSceneBranchGroup() {
    BranchGroup objRoot = super.createSceneBranchGroup();
    TransformGroup objTrans = new TransformGroup();
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
        100.0);
    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);
    rotator.setSchedulingBounds(bounds);
    objTrans.addChild(rotator);
    objTrans.addChild(new ColorCube());
    objRoot.addChild(objTrans);
    return objRoot;
  }
  public static void main(String[] args) {
    MixedTest mixedTest = new MixedTest();
    mixedTest.saveCommandLineArguments(args);
    new MainFrame(mixedTest, m_kWidth, m_kHeight);
  }
}
class ImmediateCanvas3D extends Canvas3D {
  private long m_nRender = 0;
  private long m_StartTime = 0;
  private static final int nGridSize = 50;
  private static final int m_kReportInterval = 50;
  private PointArray m_PointArray = new PointArray(nGridSize * nGridSize,
      GeometryArray.COORDINATES);
  private Transform3D m_t3d = new Transform3D();
  private float m_rot = 0.0f;
  ImmediateCanvas3D(java.awt.GraphicsConfiguration graphicsConfiguration) {
    super(graphicsConfiguration);
    // create the PointArray that we will be rendering
    int nPoint = 0;
    for (int n = 0; n < nGridSize; n++) {
      for (int i = 0; i < nGridSize; i++) {
        Point3f point = new Point3f(n - nGridSize / 2, i - nGridSize
            / 2, 0.0f);
        m_PointArray.setCoordinate(nPoint++, point);
      }
    }
  }
  public void renderField(int fieldDesc) {
    super.renderField(fieldDesc);
    GraphicsContext3D g = getGraphicsContext3D();
    // first time initialization
    if (m_nRender == 0) {
      // set the start time
      m_StartTime = System.currentTimeMillis();
      // add a light to the graphics context
      DirectionalLight light = new DirectionalLight();
      light.setEnable(true);
      g.addLight((Light) light);
      // create the material for the points
      Appearance a = new Appearance();
      Material mat = new Material();
      mat.setLightingEnable(true);
      mat.setAmbientColor(0.5f, 1.0f, 1.0f);
      a.setMaterial(mat);
      a.setColoringAttributes(new ColoringAttributes(1.0f, 0.5f, 0.5f,
          ColoringAttributes.NICEST));
      // enlarge the points
      a.setPointAttributes(new PointAttributes(4, true));
      // make the appearance current in the graphics context
      g.setAppearance(a);
    }
    // set the current transformation for the graphics context
    g.setModelTransform(m_t3d);
    // finally render the PointArray
    g.draw(m_PointArray);
    // calculate and display the Frames Per Second for the
    // Immediate Mode rendering of the PointArray
    m_nRender++;
    if ((m_nRender % m_kReportInterval) == 0) {
      float fps = (float) 1000.0f
          / ((System.currentTimeMillis() - m_StartTime) / (float) m_kReportInterval);
      System.out.println("FPS:\t" + fps);
      m_StartTime = System.currentTimeMillis();
    }
  }
  public void preRender() {
    super.preRender();
    // update the model transformation to rotate the PointArray
    // about the Y axis.
    m_rot += 0.1;
    m_t3d.rotY(m_rot);
    // move the transform back so we can see the points
    m_t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
    // scale the transformation down so we can see all of the points
    m_t3d.setScale(0.3);
    // force a paint (will call renderField)
    paint(getGraphics());
  }
}
/*******************************************************************************
 * 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;
  }
}





PrintFromButton tests renderOffScreenBuffer from a button

/*
 *  @(#)PrintFromButton.java 1.12 02/10/21 13:46:53
 *
 * 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 com.sun.j3d.utils.geometry.ColorCube;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
/**
 * PrintFromButton tests renderOffScreenBuffer from a button
 */
public class PrintFromButton extends Applet implements ActionListener {
  OffScreenCanvas3D c;
    private SimpleUniverse u = null;
  public BranchGroup createSceneGraph(Raster drawRaster)
  {
    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();
    // spin object has composited transformation matrix
    Transform3D spin = new Transform3D();
    Transform3D tempspin = new Transform3D();
    spin.rotX(Math.PI/4.0d);
    tempspin.rotY(Math.PI/5.0d);
    spin.mul(tempspin);
    spin.setScale(0.7);
    spin.setTranslation(new Vector3d(-0.4, 0.3, 0.0));
    TransformGroup objTrans = new TransformGroup(spin);
    objRoot.addChild(objTrans);
    // Create a simple shape leaf node, add it to the scene graph.
    // ColorCube is a Convenience Utility class
    objTrans.addChild(new ColorCube(0.4));
    //Create a raster obj
    Shape3D shape = new Shape3D(drawRaster);
    objRoot.addChild(shape);
    // Let Java 3D perform optimizations on this scene graph.
    objRoot.rupile();
    return objRoot;
  }
  public PrintFromButton ()
  {
  }
    public void init() {
  setLayout(new BorderLayout());
  GraphicsConfiguration config =
      SimpleUniverse.getPreferredConfiguration();
  
  BufferedImage bImage = new BufferedImage(200, 200 ,
             BufferedImage.TYPE_INT_ARGB);
  ImageComponent2D buffer =
      new ImageComponent2D(ImageComponent.FORMAT_RGBA, bImage);
  buffer.setCapability(ImageComponent2D.ALLOW_IMAGE_READ);
  Raster drawRaster = new Raster(new Point3f(0.0f, 0.0f, 0.0f),
               Raster.RASTER_COLOR,
               0, 0, 200, 200, buffer, null);
  
  drawRaster.setCapability(Raster.ALLOW_IMAGE_WRITE);
  
  // create the main scene graph
  BranchGroup scene = createSceneGraph(drawRaster);
  
  // create the on-screen canvas
  Canvas3D d = new Canvas3D(config, false);
  add("Center", d);
  
  // create a simple universe
  u = new SimpleUniverse(d);
  
  // This will move the ViewPlatform back a bit so the
  // objects in the scene can be viewed.
  u.getViewingPlatform().setNominalViewingTransform();
  
  
  // create an off Screen Buffer
  
  c = new OffScreenCanvas3D(config, true, drawRaster);
  
  // set the offscreen to match the onscreen
  Screen3D sOn = d.getScreen3D();
  Screen3D sOff = c.getScreen3D();
  sOff.setSize(sOn.getSize());
  sOff.setPhysicalScreenWidth(sOn.getPhysicalScreenWidth());
  sOff.setPhysicalScreenHeight(sOn.getPhysicalScreenHeight());
  
  // attach the same view to the offscreen canvas
  u.getViewer().getView().addCanvas3D(c);
  
  // create the gui
  Button b = new Button ("Print");
  b.addActionListener(this);
  Panel p = new Panel();
  p.add(b);
  add("North", p);
  
  u.addBranchGraph(scene);
    }
    public void destroy() {
  u.cleanup();
    }
  
  public void actionPerformed(ActionEvent e)
  {
    // perform the print action
    c.print(false);
  }
  
  public static void main(String argv[])
  {
    new MainFrame(new PrintFromButton(), 500, 500);
  }
}
class OffScreenCanvas3D extends Canvas3D {
  Raster drawRaster;
  boolean printing = false;
  public OffScreenCanvas3D(GraphicsConfiguration gconfig,
      boolean offscreenflag, Raster drawRaster) {
    super(gconfig, offscreenflag);
    this.drawRaster = drawRaster;
  }
  public void print(boolean toWait) {
    if (!toWait)
      printing = true;
    BufferedImage bImage = new BufferedImage(200, 200,
        BufferedImage.TYPE_INT_ARGB);
    ImageComponent2D buffer = new ImageComponent2D(
        ImageComponent.FORMAT_RGBA, bImage);
    buffer.setCapability(ImageComponent2D.ALLOW_IMAGE_READ);
    this.setOffScreenBuffer(buffer);
    this.renderOffScreenBuffer();
    if (toWait) {
      this.waitForOffScreenRendering();
      drawOffScreenBuffer();
    }
  }
  public void postSwap() {
    if (printing) {
      super.postSwap();
      drawOffScreenBuffer();
      printing = false;
    }
  }
  void drawOffScreenBuffer() {
    BufferedImage bImage = this.getOffScreenBuffer().getImage();
    ImageComponent2D newImageComponent = new ImageComponent2D(
        ImageComponent.FORMAT_RGBA, bImage);
    drawRaster.setImage(newImageComponent);
  }
}
class OnScreenCanvas3D extends Canvas3D {
  OffScreenCanvas3D c;
  boolean print = false;
  boolean imageReady = false;
  public OnScreenCanvas3D(GraphicsConfiguration gconfig, boolean offscreenflag) {
    super(gconfig, offscreenflag);
  }
  public void setOffScreenCanvas(OffScreenCanvas3D c) {
    this.c = c;
  }
  public void setImageReady() {
    imageReady = true;
  }
  public void postSwap() {
    if (imageReady && !print) {
      c.print(false);
      print = true;
    }
  }
}





Pure Immediate

/*
 *  @(#)PureImmediate.java 1.19 02/10/21 13:53:05
 *
 * 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.Canvas3D;
import javax.media.j3d.Geometry;
import javax.media.j3d.GraphicsContext3D;
import javax.media.j3d.Transform3D;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
/**
 * Pure immediate mode example program. In pure immediate mode, the renderer
 * must be stopped on the Canvas being rendered into. In our example, this is
 * done immediately after the canvas is created. A separate thread is started up
 * to do the immediate mode rendering.
 */
public class PureImmediate extends Applet implements Runnable {
  private Canvas3D canvas;
  private GraphicsContext3D gc = null;
  private Geometry cube = null;
  private Transform3D cmt = new Transform3D();
  // One rotation (2*PI radians) every 6 seconds
  private Alpha rotAlpha = new Alpha(-1, 6000);
  private SimpleUniverse u = null;
  //
  // Renders a single frame by clearing the canvas, drawing the
  // geometry, and swapping the draw and display buffer.
  //
  public void render() {
    if (gc == null) {
      // Set up Graphics context
      gc = canvas.getGraphicsContext3D();
      gc.setAppearance(new Appearance());
      // Set up geometry
      cube = new ColorCube(0.4).getGeometry();
    }
    // Compute angle of rotation based on alpha value
    double angle = rotAlpha.value() * 2.0 * Math.PI;
    cmt.rotY(angle);
    // Render the geometry for this frame
    gc.clear();
    gc.setModelTransform(cmt);
    gc.draw(cube);
    canvas.swap();
  }
  //
  // Run method for our immediate mode rendering thread.
  //
  public void run() {
    System.out.println("PureImmediate.run: starting main loop");
    while (true) {
      render();
      Thread.yield();
    }
  }
  public PureImmediate() {
  }
  //
  // init: create the canvas, stop the renderer,
  // create the universe, and start the drawing thread.
  //
  public void init() {
    setLayout(new BorderLayout());
    GraphicsConfiguration config = SimpleUniverse
        .getPreferredConfiguration();
    canvas = new Canvas3D(config);
    canvas.stopRenderer();
    add("Center", canvas);
    // Create the universe and viewing branch
    u = new SimpleUniverse(canvas);
    // This will move the ViewPlatform back a bit so the
    // objects in the scene can be viewed.
    u.getViewingPlatform().setNominalViewingTransform();
    // Start a new thread that will continuously render
    new Thread(this).start();
  }
  public void destroy() {
    u.cleanup();
  }
  //
  // The following allows PureImmediate to be run as an application
  // as well as an applet
  //
  public static void main(String[] args) {
    new MainFrame(new PureImmediate(), 256, 256);
  }
}





Renders a 3D shape using a 3D rendering engine that was written from scratch

/**********************************************************
 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.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.util.LinkedList;
import java.util.List;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.LineArray;
import javax.media.j3d.PointArray;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TriangleArray;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.WindowConstants;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.loaders.Scene;
import com.sun.j3d.loaders.objectfile.ObjectFile;
/**
 * Renders a 3D shape using a 3D rendering engine that was written from scratch
 * using AWT for graphics operations.
 */
public class MyJava3D extends JFrame {
  private static int m_kWidth = 400;
  private static int m_kHeight = 400;
  private RenderingEngine renderingEngine = new AwtRenderingEngine();
  private GeometryUpdater geometryUpdater = new RotatingGeometryUpdater();
  private RenderingSurface renderingSurface;
  public MyJava3D() {
    // load the object file
    Scene scene = null;
    Shape3D shape = null;
    // read in the geometry information from the data file
    ObjectFile objFileloader = new ObjectFile(ObjectFile.RESIZE);
    try {
      scene = objFileloader.load("hand1.obj");
    } catch (Exception e) {
      scene = null;
      System.err.println(e);
    }
    if (scene == null)
      System.exit(1);
    // retrieve the Shape3D object from the scene
    BranchGroup branchGroup = scene.getSceneGroup();
    shape = (Shape3D) branchGroup.getChild(0);
    GeometryArray geometryArray = (GeometryArray) shape.getGeometry();
    // add the geometry to the rendering engine...
    renderingEngine.addGeometry(geometryArray);
    // create a rendering surface and bind the rendering engine
    renderingSurface = new RenderingSurface(renderingEngine,
        geometryUpdater);
    // start the rendering surface and add it to the content panel
    renderingSurface.start();
    getContentPane().add(renderingSurface);
    // disable automatic close support for Swing frame.
    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    // adds the window listener
    addWindowListener(new WindowAdapter() {
      // handles the system exit window message
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
  }
  public static void main(String[] args) {
    MyJava3D myJava3D = new MyJava3D();
    myJava3D.setTitle("MyJava3D");
    myJava3D.setSize(300, 300);
    myJava3D.setVisible(true);
  }
}
/**
 * Definition of the RenderingEngine interface. A RenderingEngine can rendering
 * 3D geometry (described using a Java 3D GeometryArray) into a 2D Graphics
 * context.
 */
interface RenderingEngine {
  /**
   * Adds a GeometryArray to the RenderingEngine. All GeometryArrays will be
   * rendered.
   */
  public void addGeometry(GeometryArray geometryArray);
  /**
   * Renders a single frame into the Graphics.
   */
  public void render(Graphics graphics, GeometryUpdater updater);
  /**
   * Get the current Screen position used by the RenderEngine.
   */
  public Vector3d getScreenPosition();
  /**
   * Get the current View Angle used by the RenderEngine. View angles are
   * expressed in degrees.
   */
  public Vector3d getViewAngle();
  /**
   * Set the current View Angle used by the RenderEngine.
   */
  public void setViewAngle(Vector3d viewAngle);
  /**
   * Get the current View Angle used by the RenderEngine. View angles are
   * expressed in degrees.
   */
  public Vector3d getLightAngle();
  /**
   * Set the current View Angle used by the RenderEngine.
   */
  public void setLightAngle(Vector3d angle);
  /**
   * Set the Screen size used by the RenderEngine.
   */
  public void setScreenSize(int width, int height);
  /**
   * Set the scale used by the RenderEngine.
   */
  public void setScale(double scale);
  /**
   * Get the scale used by the RenderEngine.
   */
  public double getScale();
}
/**
 * Surface (JPanel) that uses a RenderingEngine to render a 3D scene. A
 * GeometryUpdater is used to update the scene and RenderEngine parameters.
 */
class RenderingSurface extends AnimatingSurface {
  RenderingEngine engine = null;
  GeometryUpdater updater = null;
  public RenderingSurface(RenderingEngine engine, GeometryUpdater updater) {
    this.engine = engine;
    this.updater = updater;
    setBackground(Color.gray);
  }
  public void render(int w, int h, Graphics2D g2) {
    engine.setScreenSize(w, h);
    engine.render(g2, updater);
  }
  public void step(int w, int h) {
  }
  public void reset(int newwidth, int newheight) {
  }
}
/**
 * Definition of the GeometryUpdater interface. GeometryUpdater instances can be
 * used to modify the geometry of a model, change RenderingEngine parameters, or
 * modify Graphics parameters during frame rendering.
 */
interface GeometryUpdater {
  public boolean update(Graphics graphics, RenderingEngine engine,
      GeometryArray geometry, int index, long frameNumber);
}
/**
 * Implementation of the RenderingEngine interface using AWT.
 */
class AwtRenderingEngine implements RenderingEngine {
  private List geometryList = null;
  private int xScreenCenter = 320 / 2;
  private int yScreenCenter = 240 / 2;
  private Vector3d screenPosition = new Vector3d(0, 0, 20);
  private Vector3d viewAngle = new Vector3d(180, 180, 180);
  private Vector3d lightAngle = new Vector3d(0, 0, 0);
  private double CT;
  private double ST;
  private double CP;
  private double SP;
  private static final double DEG_TO_RAD = 0.017453292;
  private static final int NUM_POINTS = 4;
  private int[] xCoordArray = new int[NUM_POINTS];
  private int[] yCoordArray = new int[NUM_POINTS];
  private Point3d[] pointArray = new Point3d[NUM_POINTS];
  private Point3d[] projectedPointArray = new Point3d[NUM_POINTS];
  private long frameNumber = 0;
  private static final int POINT_WIDTH = 1;
  private static final int POINT_HEIGHT = 1;
  private double modelScale = 20;
  private long startTime = 0;
  private boolean drawBackface = true;
  private boolean computeIntensity = true;
  private boolean lightRelativeToView = true;
  private Vector3d lightAngleOffset = new Vector3d(45, 45, 45);
  private Vector3f[] normalsArray = new Vector3f[NUM_POINTS];
  private Vector3f light = new Vector3f();
  private Vector3f surf_norm = new Vector3f();
  private Vector3f view = new Vector3f();
  private Vector3f temp = new Vector3f();
  private static final double lightAmbient = 0.30;
  private static final double lightDiffuse = 0.50;
  private static final double lightSpecular = 0.20;
  private static final double lightGlossiness = 5.0;
  private static final int lightMax = 255;
  public AwtRenderingEngine() {
    geometryList = new LinkedList();
    for (int n = 0; n < NUM_POINTS; n++) {
      pointArray[n] = new Point3d();
      projectedPointArray[n] = new Point3d();
      normalsArray[n] = new Vector3f();
    }
    setViewAngle(viewAngle);
    setLightAngle(lightAngle);
  }
  public void setScale(double scale) {
    modelScale = scale;
  }
  public double getScale() {
    return modelScale;
  }
  public Vector3d getScreenPosition() {
    return screenPosition;
  }
  public void setScreenSize(int width, int height) {
    xScreenCenter = width / 2;
    yScreenCenter = height / 2;
  }
  public void setScreenPosition(Vector3d screenPosition) {
    this.screenPosition = screenPosition;
  }
  public Vector3d getViewAngle() {
    return viewAngle;
  }
  public void setViewAngle(Vector3d angle) {
    this.viewAngle = angle;
    // System.out.println( "ViewAngle: " + viewAngle );
    CT = Math.cos(DEG_TO_RAD * viewAngle.x);
    ST = Math.sin(DEG_TO_RAD * viewAngle.x);
    CP = Math.cos(DEG_TO_RAD * viewAngle.y);
    SP = Math.sin(DEG_TO_RAD * viewAngle.y);
    view.x = (float) (-CP * ST);
    view.y = (float) (-CP * CT);
    view.z = (float) SP;
    if (lightRelativeToView != false) {
      lightAngle.x = viewAngle.x + lightAngleOffset.x;
      lightAngle.y = viewAngle.y + lightAngleOffset.y;
      lightAngle.z = viewAngle.z + lightAngleOffset.z;
      setLightAngle(lightAngle);
    }
  }
  public Vector3d getLightAngle() {
    return lightAngle;
  }
  public void setLightAngle(Vector3d angle) {
    this.lightAngle = angle;
    //System.out.println( "LightAngle: " + lightAngle );
    CT = Math.cos(DEG_TO_RAD * viewAngle.x);
    ST = Math.sin(DEG_TO_RAD * viewAngle.x);
    CP = Math.cos(DEG_TO_RAD * viewAngle.y);
    SP = Math.sin(DEG_TO_RAD * viewAngle.y);
    light.x = (float) (Math.sin(DEG_TO_RAD * lightAngle.y) * Math
        .cos(DEG_TO_RAD * lightAngle.x));
    light.y = (float) (Math.sin(DEG_TO_RAD * lightAngle.y) * Math
        .sin(DEG_TO_RAD * lightAngle.x));
    light.z = (float) (Math.cos(DEG_TO_RAD * lightAngle.y));
  }
  public void addGeometry(GeometryArray geometryArray) {
    System.out.println("Adding GeometryArray: " + geometryArray);
    geometryList.add(geometryArray);
  }
  public void renderGeometry(Graphics graphics, GeometryUpdater updater) {
    GeometryArray geomArray;
    for (int n = 0; n < geometryList.size(); n++) {
      geomArray = (GeometryArray) geometryList.get(n);
      if (geomArray instanceof LineArray) {
        renderLineArray(graphics, updater, geomArray);
      } else if (geomArray instanceof PointArray) {
        renderPointArray(graphics, updater, geomArray);
      } else if (geomArray instanceof QuadArray) {
        renderQuadArray(graphics, updater, geomArray);
      } else if (geomArray instanceof TriangleArray) {
        renderTriangleArray(graphics, updater, geomArray);
      } else {
        throw new UnsupportedOperationException(
            "Unknown geometry type: " + geomArray);
      }
    }
  }
  public void renderLineArray(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray) {
    for (int n = 0; n < geometryArray.getVertexCount(); n += 2)
      drawLine(graphics, updater, geometryArray, n);
  }
  public void renderPointArray(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray) {
    for (int n = 0; n < geometryArray.getVertexCount(); n++)
      drawPoint(graphics, updater, geometryArray, n);
  }
  public void renderQuadArray(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray) {
    for (int n = 0; n < geometryArray.getVertexCount(); n += 4)
      drawQuad(graphics, updater, geometryArray, n);
  }
  public void renderTriangleArray(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray) {
    for (int n = 0; n < geometryArray.getVertexCount(); n += 3)
      drawTriangle(graphics, updater, geometryArray, n);
  }
  public void render(Graphics graphics, GeometryUpdater updater) {
    if (frameNumber == 0)
      startTime = System.currentTimeMillis();
    renderGeometry(graphics, updater);
    frameNumber++;
    if (frameNumber % 500 == 0) {
      System.out.println("FPS: "
          + ((double) 500 / (System.currentTimeMillis() - startTime))
          * 1000.0);
      startTime = System.currentTimeMillis();
    }
  }
  public void projectPoint(Point3d input, Point3d output) {
    double x = screenPosition.x + input.x * CT - input.y * ST;
    double y = screenPosition.y + input.x * ST * SP + input.y * CT * SP
        + input.z * CP;
    double temp = viewAngle.z
        / (screenPosition.z + input.x * ST * CP + input.y * CT * CP - input.z
            * SP);
    output.x = xScreenCenter + modelScale * temp * x;
    output.y = yScreenCenter - modelScale * temp * y;
    output.z = 0;
  }
  public void drawLine(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray, int index) {
    for (int n = 0; n < 2; n++) {
      updater.update(graphics, this, geometryArray, index + n,
          frameNumber);
      geometryArray.getCoordinate(index + n, pointArray[n]);
    }
    for (int n = 0; n < 2; n++)
      projectPoint(pointArray[n], projectedPointArray[n]);
    drawLine(graphics, geometryArray, index, projectedPointArray);
  }
  public void drawLine(Graphics graphics, GeometryArray geometryArray,
      int index, Point3d[] pointArray) {
    int intensity = computeIntensity(geometryArray, index, 2);
    if (drawBackface || intensity >= 1) {
      graphics.setColor(new Color(intensity, intensity, intensity));
      graphics.drawLine((int) pointArray[0].x, (int) pointArray[0].y,
          (int) pointArray[1].x, (int) pointArray[1].y);
    }
  }
  public void drawQuad(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray, int index) {
    for (int n = 0; n < 4; n++)
      updater.update(graphics, this, geometryArray, index + n,
          frameNumber);
    geometryArray.getCoordinates(index, pointArray);
    for (int n = 0; n < 4; n++)
      projectPoint(pointArray[n], projectedPointArray[n]);
    drawQuad(graphics, geometryArray, index, projectedPointArray);
  }
  public void drawQuad(Graphics graphics, GeometryArray geometryArray,
      int index, Point3d[] pointArray) {
    drawFacet(graphics, geometryArray, index, pointArray, 4);
  }
  private void averageVector(Vector3f returnVector, Vector3f[] vectorArray,
      int numPoints) {
    float x = 0;
    float y = 0;
    float z = 0;
    for (int n = 0; n < numPoints; n++) {
      x += vectorArray[n].x;
      y += vectorArray[n].y;
      z += vectorArray[n].z;
    }
    returnVector.x = x / numPoints;
    returnVector.y = y / numPoints;
    returnVector.z = z / numPoints;
  }
  private int computeIntensity(GeometryArray geometryArray, int index,
      int numPoints) {
    int intensity = 0;
    if (computeIntensity != false) {
      // if we have a normal vector compute the intensity under the
      // lighting
      if ((geometryArray.getVertexFormat() & GeometryArray.NORMALS) == GeometryArray.NORMALS) {
        double cos_theta;
        double cos_alpha;
        double cos_beta;
        for (int n = 0; n < numPoints; n++)
          geometryArray.getNormal(index + n, normalsArray[n]);
        // take the average normal vector
        averageVector(surf_norm, normalsArray, numPoints);
        temp.set(view);
        temp.scale(1.0f, surf_norm);
        cos_beta = temp.x + temp.y + temp.z;
        if (cos_beta > 0.0) {
          cos_theta = surf_norm.dot(light);
          if (cos_theta <= 0.0) {
            intensity = (int) (lightMax * lightAmbient);
          } else {
            temp.set(surf_norm);
            temp.scale((float) cos_theta);
            temp.normalize();
            temp.sub(light);
            temp.normalize();
            cos_alpha = view.dot(temp);
            intensity = (int) (lightMax * (lightAmbient
                + lightDiffuse * cos_theta + lightSpecular
                * Math.pow(cos_alpha, lightGlossiness)));
          }
        }
      }
    }
    return intensity;
  }
  public void drawFacet(Graphics graphics, GeometryArray geometryArray,
      int index, Point3d[] pointArray, int numPoints) {
    int intensity = computeIntensity(geometryArray, index, numPoints);
    if (drawBackface || intensity >= 1) {
      for (int n = 0; n < numPoints; n++) {
        xCoordArray[n] = (int) pointArray[n].x;
        yCoordArray[n] = (int) pointArray[n].y;
      }
      graphics.setColor(new Color(intensity, intensity, intensity));
      graphics.drawPolygon(xCoordArray, yCoordArray, numPoints);
    }
  }
  public void drawPoint(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray, int index) {
    updater.update(graphics, this, geometryArray, index, frameNumber);
    geometryArray.getCoordinate(index, pointArray[0]);
    projectPoint(pointArray[0], projectedPointArray[0]);
    drawPoint(graphics, projectedPointArray);
  }
  public void drawPoint(Graphics graphics, Point3d[] pointArray) {
    graphics.drawRect((int) pointArray[0].x, (int) pointArray[0].y,
        POINT_WIDTH, POINT_HEIGHT);
  }
  public void drawTriangle(Graphics graphics, GeometryUpdater updater,
      GeometryArray geometryArray, int index) {
    for (int n = 0; n < 3; n++) {
      updater.update(graphics, this, geometryArray, (index + n),
          frameNumber);
      geometryArray.getCoordinate((index + n), pointArray[n]);
    }
    for (int n = 0; n < 3; n++)
      projectPoint(pointArray[n], projectedPointArray[n]);
    drawTriangle(graphics, geometryArray, index, projectedPointArray);
  }
  public void drawTriangle(Graphics graphics, GeometryArray geometryArray,
      int index, Point3d[] pointArray) {
    drawFacet(graphics, geometryArray, index, pointArray, 3);
  }
}
/**
 * This class implements a rendering surface that will repaint itself
 * continiously using a low-priority thread.
 * <p>
 * This class is based on the Java 2D demo examples.
 */
abstract class AnimatingSurface extends Surface implements Runnable {
  public Thread thread;
  public abstract void step(int w, int h);
  public abstract void reset(int newwidth, int newheight);
  public void start() {
    if (thread == null) {
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.start();
    }
  }
  public synchronized void stop() {
    if (thread != null) {
      thread.interrupt();
    }
    thread = null;
    notifyAll();
  }
  public void run() {
    Thread me = Thread.currentThread();
    while (thread == me && !isShowing() || getSize().width == 0) {
      try {
        thread.sleep(200);
      } catch (InterruptedException e) {
      }
    }
    while (thread == me) {
      repaint();
    }
    thread = null;
  }
}
/**
 * The Surface class implements a 2D rendering surface using a Swing JPanel. The
 * Surface can contain an AlphaComposite and a background Texture as well as
 * foreground rendered output.
 * <p>
 * The Surface can have anti-aliasing enabled and be optimized for speed or
 * quality.
 * <p>
 * This class is based on that found in the Java 2D examples.
 */
abstract class Surface extends JPanel implements Printable {
  public Object AntiAlias = RenderingHints.VALUE_ANTIALIAS_OFF;
  public Object Rendering = RenderingHints.VALUE_RENDER_SPEED;
  public AlphaComposite composite;
  public Paint texture;
  public String perfStr; // PerformanceMonitor
  public BufferedImage bimg;
  public int imageType;
  public String name;
  public boolean clearSurface = true;
  public AnimatingSurface animating;
  protected long sleepAmount = 0;
  private long orig, start, frame;
  private Toolkit toolkit;
  private int biw, bih;
  private boolean clearOnce;
  public Surface() {
    toolkit = getToolkit();
    setImageType(0);
    if (this instanceof AnimatingSurface) {
      animating = (AnimatingSurface) this;
    }
  }
  public int getImageType() {
    return imageType;
  }
  public void setImageType(int imgType) {
    if (imgType == 0) {
      if (this instanceof AnimatingSurface) {
        imageType = 2;
      } else {
        imageType = 1;
      }
    } else {
      imageType = imgType;
    }
    bimg = null;
  }
  public void setAntiAlias(boolean aa) {
    AntiAlias = aa ? RenderingHints.VALUE_ANTIALIAS_ON
        : RenderingHints.VALUE_ANTIALIAS_OFF;
  }
  public void setRendering(boolean rd) {
    Rendering = rd ? RenderingHints.VALUE_RENDER_QUALITY
        : RenderingHints.VALUE_RENDER_SPEED;
  }
  public void setTexture(Object obj) {
    if (obj instanceof GradientPaint) {
      texture = new GradientPaint(0, 0, Color.white, getSize().width * 2,
          0, Color.green);
    } else {
      texture = (Paint) obj;
    }
  }
  public void setComposite(boolean cp) {
    composite = cp ? AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
        0.5f) : null;
  }
  public void setSleepAmount(long amount) {
    sleepAmount = amount;
  }
  public long getSleepAmount() {
    return sleepAmount;
  }
  public BufferedImage createBufferedImage(int w, int h, int imgType) {
    BufferedImage bi = null;
    if (imgType == 0) {
      bi = (BufferedImage) createImage(w, h);
    } else if (imgType > 0 && imgType < 14) {
      bi = new BufferedImage(w, h, imgType);
    } else if (imgType == 14) {
      bi = createBinaryImage(w, h, 2);
    } else if (imgType == 15) {
      bi = createBinaryImage(w, h, 4);
    }
    biw = w;
    bih = h;
    return bi;
  }
  // Lookup tables for BYTE_BINARY 1, 2 and 4 bits.
  static byte[] lut1Arr = new byte[] { 0, (byte) 255 };
  static byte[] lut2Arr = new byte[] { 0, (byte) 85, (byte) 170, (byte) 255 };
  static byte[] lut4Arr = new byte[] { 0, (byte) 17, (byte) 34, (byte) 51,
      (byte) 68, (byte) 85, (byte) 102, (byte) 119, (byte) 136,
      (byte) 153, (byte) 170, (byte) 187, (byte) 204, (byte) 221,
      (byte) 238, (byte) 255 };
  private BufferedImage createBinaryImage(int w, int h, int pixelBits) {
    int[] pixels = new int[w * h];
    int bytesPerRow = w * pixelBits / 8;
    if (w * pixelBits % 8 != 0) {
      bytesPerRow++;
    }
    byte[] imageData = new byte[h * bytesPerRow];
    IndexColorModel cm = null;
    switch (pixelBits) {
    case 1:
      cm = new IndexColorModel(pixelBits, lut1Arr.length, lut1Arr,
          lut1Arr, lut1Arr);
      break;
    case 2:
      cm = new IndexColorModel(pixelBits, lut2Arr.length, lut2Arr,
          lut2Arr, lut2Arr);
      break;
    case 4:
      cm = new IndexColorModel(pixelBits, lut4Arr.length, lut4Arr,
          lut4Arr, lut4Arr);
      break;
    default: {
      new Exception("Invalid # of bit per pixel").printStackTrace();
    }
    }
    DataBuffer db = new DataBufferByte(imageData, imageData.length);
    WritableRaster r = Raster.createPackedRaster(db, w, h, pixelBits, null);
    return new BufferedImage(cm, r, false, null);
  }
  public Graphics2D createGraphics2D(int width, int height, BufferedImage bi,
      Graphics g) {
    Graphics2D g2 = null;
    if (bi != null) {
      g2 = bi.createGraphics();
    } else {
      g2 = (Graphics2D) g;
    }
    g2.setBackground(getBackground());
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, AntiAlias);
    g2.setRenderingHint(RenderingHints.KEY_RENDERING, Rendering);
    if (clearSurface || clearOnce) {
      g2.clearRect(0, 0, width, height);
      clearOnce = false;
    }
    if (texture != null) {
      // set composite to opaque for texture fills
      g2.setComposite(AlphaComposite.SrcOver);
      g2.setPaint(texture);
      g2.fillRect(0, 0, width, height);
    }
    if (composite != null) {
      g2.setComposite(composite);
    }
    return g2;
  }
  // ...demos that extend Surface must implement this routine...
  public abstract void render(int w, int h, Graphics2D g2);
  /**
   * It"s possible to turn off double-buffering for just the repaint calls
   * invoked directly on the non double buffered component. This can be done
   * by overriding paintImmediately() (which is called as a result of repaint)
   * and getting the current RepaintManager and turning off double buffering
   * in the RepaintManager before calling super.paintImmediately(g).
   */
  public void paintImmediately(int x, int y, int w, int h) {
    RepaintManager repaintManager = null;
    boolean save = true;
    if (!isDoubleBuffered()) {
      repaintManager = RepaintManager.currentManager(this);
      save = repaintManager.isDoubleBufferingEnabled();
      repaintManager.setDoubleBufferingEnabled(false);
    }
    super.paintImmediately(x, y, w, h);
    if (repaintManager != null) {
      repaintManager.setDoubleBufferingEnabled(save);
    }
  }
  public void paint(Graphics g) {
    Dimension d = getSize();
    if (imageType == 1) {
      bimg = null;
      startClock();
    } else if (bimg == null || biw != d.width || bih != d.height) {
      if (animating != null && (biw != d.width || bih != d.height)) {
        animating.reset(d.width, d.height);
      }
      bimg = createBufferedImage(d.width, d.height, imageType - 2);
      clearOnce = true;
      startClock();
    }
    if (animating != null && animating.thread != null) {
      animating.step(d.width, d.height);
    }
    Graphics2D g2 = createGraphics2D(d.width, d.height, bimg, g);
    render(d.width, d.height, g2);
    g2.dispose();
    if (bimg != null) {
      g.drawImage(bimg, 0, 0, null);
      toolkit.sync();
    }
  }
  public int print(Graphics g, PageFormat pf, int pi) throws PrinterException {
    if (pi >= 1) {
      return Printable.NO_SUCH_PAGE;
    }
    Graphics2D g2d = (Graphics2D) g;
    g2d.translate(pf.getImageableX(), pf.getImageableY());
    g2d.translate(pf.getImageableWidth() / 2, pf.getImageableHeight() / 2);
    Dimension d = getSize();
    double scale = Math.min(pf.getImageableWidth() / d.width, pf
        .getImageableHeight()
        / d.height);
    if (scale < 1.0) {
      g2d.scale(scale, scale);
    }
    g2d.translate(-d.width / 2.0, -d.height / 2.0);
    if (bimg == null) {
      Graphics2D g2 = createGraphics2D(d.width, d.height, null, g2d);
      render(d.width, d.height, g2);
      g2.dispose();
    } else {
      g2d.drawImage(bimg, 0, 0, this);
    }
    return Printable.PAGE_EXISTS;
  }
  private void startClock() {
    orig = System.currentTimeMillis();
    start = orig;
  }
}
/**
 * Implementation of the GeometryUpdater interface. That rotates the scene by
 * changing the viewer position and the scale factor for the model.
 */
class RotatingGeometryUpdater implements GeometryUpdater {
  long lastFrame = -1;
  public RotatingGeometryUpdater() {
  }
  public boolean update(Graphics graphics, RenderingEngine engine,
      GeometryArray geometry, int index, long frameNumber) {
    if (lastFrame != frameNumber) {
      lastFrame = frameNumber;
      Vector3d viewAngle = engine.getViewAngle();
      viewAngle.x += 1;
      //viewAngle.y += 2;
      engine.setViewAngle(viewAngle);
      //Vector3d lightAngle = engine.getLightAngle( );
      //lightAngle.x += 5;
      //lightAngle.y += 2;
      //engine.setLightAngle( lightAngle );
      //engine.setScale( (50 * Math.sin( Math.PI *
      // (System.currentTimeMillis() % 5000) / 5000.0 )) + 1 );
    }
    return false;
  }
}
// File: hand1.obj
/*
# Mon Jun 02 17:09:33 1997
#
#
g hand1
v -0.551223 0.307562 -3.946050
v -0.215465 0.030475 -3.703516
v -0.059140 0.068255 -1.551531
v -0.487235 0.455792 -4.006029
v -0.168743 0.090975 -3.755638
v -0.338689 0.569450 -4.244848
v -0.639211 0.502297 -4.165243
v -0.760687 0.647871 -4.482797
v -0.529792 0.073768 -3.945949
v -0.707612 0.258064 -4.192451
v -0.866004 0.446161 -4.511733
v -0.367733 -0.147323 -4.191223
v -0.717413 0.071719 -4.433171
v -0.893823 0.253971 -4.589350
v -0.172976 -0.188212 -3.754734
v -0.089148 -0.103984 -1.450071
v -0.234491 -0.100206 -3.756646
v -0.131305 -0.032994 -1.531782
v -0.589492 0.641054 -4.376035
v -0.050594 -0.257375 -4.417058
v 0.208857 -0.205637 -4.768191
v 0.007882 -0.231806 -4.028160
v 0.230232 -0.186379 -4.335583
v 0.390435 -0.043258 -4.060836
v 0.002626 -0.129308 -1.430840
v -0.058465 -0.217994 -3.717670
v 0.087189 -0.100005 -1.425612
v 0.044163 -0.171797 -3.707954
v 0.044240 0.657156 -4.536777
v -0.137070 0.604272 -4.344090
v 0.041139 0.604901 -4.118776
v -0.080844 0.531805 -3.993031
v 0.165095 0.484110 -3.906230
v -0.081629 0.087632 -3.782753
v -0.013872 0.088823 -1.554481
v 0.008630 0.041677 -3.708195
v 0.070162 0.059225 -1.467241
v 0.349126 0.784380 -4.327246
v 0.192656 0.707311 -4.316467
v 0.240026 0.669896 -4.092967
v 0.614077 0.770599 -4.245997
v 0.448901 0.789330 -4.242595
v 0.390683 0.635870 -4.050064
v 0.823568 1.030378 -5.230011
v 0.583262 0.935220 -4.789198
v 0.936485 1.075914 -5.144932
v 0.708930 0.972489 -4.713959
v 1.079595 1.050653 -5.079602
v 0.863290 0.942616 -4.657226
v 0.731356 0.950572 -5.335061
v 0.698927 0.816156 -5.569689
v 0.452954 0.862935 -4.860037
v 0.354245 0.777679 -5.103039
v 0.109515 -0.020305 -1.439012
v 0.321579 0.190660 -3.847763
v 0.056950 -0.068344 -3.678991
v 0.551677 0.397382 -4.027330
v 0.748943 0.261978 -4.201552
v 0.797463 0.611225 -4.241810
v 0.934536 0.472987 -4.298673
v 0.919641 0.370477 -5.597496
v 1.079582 0.375487 -5.341094
v 1.225601 0.456396 -5.207421
v 0.593068 0.043314 -5.202118
v 0.711852 0.101000 -4.865152
v 0.871615 0.211454 -4.690717
v 1.063296 0.399320 -4.647913
v 1.342637 0.585582 -5.122607
v 1.150690 0.608137 -4.641154
v 1.366648 0.748651 -5.071675
v 0.745367 0.246406 -5.988852
v 0.494019 -0.022198 -5.740361
v 0.141480 -0.193021 -5.470416
v 0.693354 0.148862 -6.455598
v 0.458179 -0.058425 -6.342125
v 0.092861 -0.121753 -6.334044
v 0.001903 0.615014 -5.359071
v 0.310613 0.694999 -5.659912
v 0.602326 0.700149 -5.960638
v 0.014377 0.478587 -6.304075
v 0.335968 0.619833 -6.312831
v 0.600780 0.612337 -6.446789
v -0.303419 0.594566 -6.098518
v -0.599974 0.655996 -6.132385
v -0.241202 0.626083 -5.200386
v -0.457099 0.677790 -5.161324
v -0.259616 -0.163854 -6.116562
v -0.183392 -0.223625 -5.241480
v -0.635209 0.061396 -6.121774
v -0.504788 -0.103060 -5.122423
v -0.950019 0.234128 -5.837874
v -0.810067 0.092804 -5.080121
v -1.144829 0.478824 -5.746136
v -0.998398 0.334709 -5.084644
v -0.994164 0.856674 -5.773610
v -0.863354 0.756330 -5.102725
v -0.801998 0.842826 -5.870856
v -0.671650 0.764754 -5.123487
v 1.045049 0.802118 -4.632644
v 1.252493 0.924338 -5.055513
v -0.995449 0.583125 -5.083862
v -1.137996 0.713069 -5.735577
v 1.598002 0.816988 -5.564189
v 1.599381 0.700758 -5.624741
v 1.532017 0.614642 -5.716787
v 1.715526 0.933794 -5.717422
v 1.699604 0.816034 -5.787023
v 1.629737 0.731598 -5.898082
v 1.883043 1.059492 -5.899169
v 1.855109 0.932664 -5.998640
v 1.774384 0.842472 -6.140775
v 1.424351 0.559021 -5.523375
v 1.505227 0.658051 -5.434678
v 1.502338 0.787710 -5.373565
v 1.297397 0.577850 -5.903827
v 1.425129 0.560695 -5.822476
v 1.155962 0.509306 -5.718982
v 1.300644 0.494656 -5.623770
v 1.509245 0.835318 -6.384689
v 1.646807 0.801147 -6.286009
v 1.406474 0.713747 -6.133959
v 1.525574 0.687385 -6.031679
v 1.380351 1.065119 -5.565239
v 1.564172 1.172023 -5.714888
v 1.780605 1.304970 -5.893034
v 1.255719 1.087198 -5.619839
v 1.438416 1.182678 -5.766468
v 1.652418 1.312790 -5.952035
v 1.154437 1.043031 -5.702960
v 1.320461 1.134701 -5.855917
v 1.512782 1.262635 -6.051604
v 1.003945 1.036752 -5.521133
v 1.104476 1.081637 -5.435655
v 1.236055 1.056913 -5.374795
v 1.089111 0.843044 -5.888583
v 1.089661 0.962064 -5.803318
v 1.230625 0.966122 -6.097103
v 1.242952 1.066407 -5.981094
v 1.362597 1.098246 -6.323909
v 1.405432 1.196541 -6.191591
v 0.929064 0.824679 -5.709339
v 0.934340 0.953520 -5.615597
v 1.859089 1.203879 -5.868989
v 1.664971 1.072200 -5.695913
v 1.510868 0.957577 -5.544997
v 1.391678 0.940769 -5.352942
v 1.170557 0.692380 -5.926214
v 1.027666 0.653090 -5.757548
v 0.869972 0.619560 -5.748698
v 1.295478 0.827279 -6.155195
v 1.403801 0.956111 -6.395917
v 1.981874 0.878914 -6.465936
v 1.802272 0.826665 -6.577847
v 1.615752 0.851027 -6.620514
v 2.128560 0.944598 -6.721747
v 1.907593 0.869058 -6.790360
v 1.708489 0.849226 -6.769275
v 2.238363 1.116521 -6.349912
v 2.094190 1.105140 -6.141595
v 2.237261 1.035889 -6.535950
v 2.075505 0.976585 -6.291769
v 1.727506 1.346013 -6.328338
v 1.936762 1.311864 -6.600124
v 1.576315 1.256378 -6.447272
v 1.741231 1.205721 -6.680005
v 1.483882 1.132384 -6.546886
v 1.595348 1.106596 -6.700094
v 2.143625 1.363027 -6.343407
v 2.083770 1.364678 -6.472173
v 1.997907 1.370713 -6.136065
v 1.880283 1.392692 -6.219747
v 2.220069 1.245977 -6.358671
v 2.223785 1.204368 -6.587201
v 2.097329 1.131385 -6.757537
v 1.644286 0.966614 -6.763514
v 1.867680 1.032451 -6.812611
v 0.883363 0.124343 -7.228944
v 0.646839 -0.024425 -7.259110
v 0.390212 -0.005959 -7.292361
v 1.070393 0.135169 -7.703971
v 0.802047 0.006235 -7.763816
v 0.511476 0.026061 -7.813804
v 1.163011 0.161832 -8.064369
v 0.918797 0.093289 -8.161346
v 0.636154 0.076768 -8.160398
v 0.269275 -0.049054 -6.787587
v 0.524823 -0.050661 -6.806285
v 0.744409 0.117607 -6.839493
v 0.827585 0.571806 -7.238711
v 1.016438 0.562215 -7.711038
v 1.115469 0.520019 -8.067395
v 0.573132 0.588769 -7.270417
v 0.731449 0.578986 -7.772986
v 0.865027 0.502425 -8.164807
v 0.338782 0.438496 -7.299040
v 0.460865 0.446711 -7.820236
v 0.590458 0.430524 -8.163703
v 0.208617 0.434283 -6.784674
v 0.437333 0.591011 -6.807528
v 0.678646 0.577267 -6.844694
v 0.947532 0.372788 -7.222228
v 0.797216 0.376391 -6.856188
v 0.734974 0.417910 -6.504792
v 1.142651 0.368565 -7.694477
v 1.195867 0.347815 -8.107895
v 0.272439 0.191555 -7.307303
v 0.163854 0.163934 -6.807784
v 0.050485 0.143298 -6.551455
v 0.390845 0.216656 -7.842326
v 0.587957 0.247899 -8.218260
v -0.187159 -0.021301 -8.489817
v -0.144520 -0.066015 -8.115219
v -0.135056 -0.086523 -7.519433
v -0.455856 -0.036286 -8.505733
v -0.424768 -0.127085 -8.081474
v -0.379623 -0.149656 -7.480232
v -0.721089 0.002465 -8.418228
v -0.711949 -0.032964 -8.033904
v -0.633023 -0.036474 -7.439595
v -0.083764 -0.101907 -6.888419
v -0.321252 -0.155635 -6.827525
v -0.570598 -0.013135 -6.792706
v -0.205536 0.346922 -8.488331
v -0.478068 0.389386 -8.503635
v -0.741261 0.375015 -8.416031
v -0.166164 0.372104 -8.112885
v -0.454556 0.470532 -8.077909
v -0.734413 0.413380 -8.030973
v -0.161420 0.377122 -7.515023
v -0.412007 0.496828 -7.474960
v -0.653762 0.440220 -7.436335
v -0.124968 0.400042 -6.878002
v -0.359615 0.536135 -6.818819
v -0.582637 0.502600 -6.791322
v -0.736234 0.212481 -7.423101
v -0.655151 0.259193 -6.812274
v -0.663333 0.364684 -6.389957
v -0.775997 0.191334 -8.463245
v -0.822719 0.196893 -8.024588
v -0.031942 0.130966 -6.924860
v -0.055396 0.134692 -7.532089
v -0.056604 0.146553 -8.134798
v -0.157928 0.161766 -8.546125
v -1.836226 1.016590 -7.410828
v -1.627684 0.872918 -7.538481
v -1.370280 0.758218 -7.595252
v -1.747767 0.932613 -7.142950
v -1.528535 0.732919 -7.246038
v -1.256016 0.658972 -7.340291
v -1.538345 0.794709 -6.746178
v -1.346968 0.594312 -6.836720
v -1.106538 0.540492 -6.926594
v -1.327304 0.638226 -6.296957
v -1.144801 0.423090 -6.386161
v -0.907648 0.349198 -6.500935
v -1.381548 1.162123 -6.749738
v -1.167106 1.131764 -6.834267
v -1.001718 0.954827 -6.919466
v -1.579033 1.276060 -7.151250
v -1.336962 1.223187 -7.246882
v -1.140912 1.040889 -7.333368
v -1.682336 1.295016 -7.423892
v -1.479018 1.212733 -7.544489
v -1.266431 1.072053 -7.592119
v -1.173291 1.003628 -6.309747
v -0.980917 0.984092 -6.395974
v -0.826961 0.810684 -6.501183
v -0.978037 0.704393 -6.955856
v -1.119137 0.806439 -7.374477
v -1.298471 0.903687 -7.643332
v -0.811802 0.542748 -6.562383
v -1.320080 0.864534 -6.271852
v -1.536038 1.021683 -6.715133
v -1.746360 1.149667 -7.118443
v -1.808232 1.181964 -7.439637
v 2.071132 1.255908 -6.105393
v 1.505985 0.975476 -6.611821
v 0.931009 0.299286 -8.285854
v -0.474965 0.178488 -8.633644
v -1.589683 1.061216 -7.631387
v 0.763920 0.520049 -6.078023
# 281 vertices
# 0 texture vertices
# 0 normals
usemtl hand
f 2 4 1
f 5 4 2
f 3 5 2
f 5 6 4
f 1 10 9
f 1 7 10
f 7 11 10
f 7 8 11
f 10 12 9
f 12 10 13
f 10 14 13
f 10 11 14
f 12 17 9
f 12 15 17
f 18 15 16
f 15 18 17
f 9 2 1
f 9 17 2
f 18 2 17
f 2 18 3
f 19 4 6
f 7 4 19
f 8 7 19
f 7 1 4
f 20 22 12
f 23 22 20
f 21 23 20
f 23 24 22
f 16 26 25
f 16 15 26
f 15 22 26
f 15 12 22
f 25 28 27
f 25 26 28
f 22 28 26
f 28 22 24
f 30 31 29
f 32 31 30
f 6 32 30
f 32 33 31
f 5 32 6
f 32 5 34
f 5 35 34
f 5 3 35
f 34 33 32
f 33 34 36
f 35 36 34
f 36 35 37
f 39 40 38
f 31 40 39
f 29 31 39
f 31 33 40
f 42 43 41
f 40 43 42
f 38 40 42
f 40 33 43
f 45 46 44
f 46 45 47
f 38 47 45
f 47 38 42
f 46 49 48
f 46 47 49
f 47 41 49
f 47 42 41
f 44 52 45
f 44 50 52
f 50 53 52
f 50 51 53
f 52 38 45
f 38 52 39
f 52 29 39
f 52 53 29
f 36 55 33
f 55 36 56
f 37 56 36
f 56 37 54
f 56 24 55
f 24 56 28
f 27 56 54
f 56 27 28
f 33 57 43
f 33 55 57
f 55 58 57
f 55 24 58
f 57 41 43
f 41 57 59
f 58 59 57
f 59 58 60
f 62 64 61
f 64 62 65
f 63 65 62
f 65 63 66
f 65 21 64
f 21 65 23
f 66 23 65
f 23 66 24
f 66 58 24
f 58 66 67
f 63 67 66
f 67 63 68
f 67 60 58
f 60 67 69
f 68 69 67
f 69 68 70
f 61 72 71
f 61 64 72
f 64 73 72
f 64 21 73
f 71 75 74
f 71 72 75
f 72 76 75
f 72 73 76
f 53 77 29
f 77 53 78
f 51 78 53
f 78 51 79
f 78 80 77
f 80 78 81
f 79 81 78
f 81 79 82
f 83 77 80
f 77 83 85
f 83 86 85
f 83 84 86
f 85 29 77
f 29 85 30
f 86 30 85
f 30 86 6
f 73 87 76
f 87 73 88
f 21 88 73
f 88 21 20
f 88 89 87
f 89 88 90
f 20 90 88
f 90 20 12
f 90 91 89
f 91 90 92
f 90 13 92
f 90 12 13
f 91 94 93
f 91 92 94
f 92 14 94
f 92 13 14
f 95 98 97
f 95 96 98
f 8 98 96
f 98 8 19
f 97 86 84
f 97 98 86
f 19 86 98
f 86 19 6
f 59 49 41
f 49 59 99
f 59 69 99
f 59 60 69
f 99 48 49
f 48 99 100
f 99 70 100
f 99 69 70
f 8 101 11
f 8 96 101
f 96 102 101
f 96 95 102
f 101 14 11
f 14 101 94
f 101 93 94
f 101 102 93
f 103 107 106
f 103 104 107
f 105 107 104
f 107 105 108
f 107 109 106
f 109 107 110
f 108 110 107
f 110 108 111
f 63 113 68
f 63 112 113
f 112 104 113
f 112 105 104
f 68 114 70
f 68 113 114
f 113 103 114
f 113 104 103
f 115 118 117
f 115 116 118
f 105 118 116
f 118 105 112
f 117 62 61
f 117 118 62
f 112 62 118
f 62 112 63
f 120 121 119
f 121 120 122
f 111 122 120
f 122 111 108
f 122 115 121
f 115 122 116
f 108 116 122
f 116 108 105
f 123 127 126
f 123 124 127
f 124 128 127
f 124 125 128
f 126 130 129
f 126 127 130
f 127 131 130
f 127 128 131
f 44 133 132
f 44 46 133
f 48 133 46
f 133 48 134
f 132 126 129
f 132 133 126
f 134 126 133
f 126 134 123
f 135 138 137
f 135 136 138
f 136 130 138
f 136 129 130
f 137 140 139
f 137 138 140
f 138 131 140
f 138 130 131
f 51 142 141
f 51 50 142
f 50 132 142
f 50 44 132
f 141 136 135
f 141 142 136
f 142 129 136
f 142 132 129
f 109 144 106
f 109 143 144
f 125 144 143
f 144 125 124
f 106 145 103
f 106 144 145
f 124 145 144
f 145 124 123
f 100 134 48
f 134 100 146
f 70 146 100
f 146 70 114
f 146 123 134
f 123 146 145
f 114 145 146
f 145 114 103
f 135 148 141
f 135 147 148
f 147 117 148
f 147 115 117
f 141 149 51
f 141 148 149
f 148 61 149
f 148 117 61
f 115 150 121
f 115 147 150
f 135 150 147
f 150 135 137
f 121 151 119
f 121 150 151
f 137 151 150
f 151 137 139
f 120 152 111
f 152 120 153
f 119 153 120
f 153 119 154
f 152 156 155
f 152 153 156
f 153 157 156
f 153 154 157
f 158 161 160
f 158 159 161
f 159 110 161
f 159 109 110
f 160 152 155
f 160 161 152
f 161 111 152
f 161 110 111
f 162 140 131
f 140 162 164
f 162 165 164
f 162 163 165
f 164 139 140
f 139 164 166
f 164 167 166
f 164 165 167
f 168 171 170
f 168 169 171
f 163 171 169
f 171 163 162
f 171 125 170
f 125 171 128
f 162 128 171
f 128 162 131
f 172 169 168
f 169 172 173
f 158 173 172
f 173 158 160
f 169 174 163
f 169 173 174
f 160 174 173
f 174 160 155
f 157 176 156
f 157 175 176
f 167 176 175
f 176 167 165
f 176 155 156
f 155 176 174
f 176 163 174
f 176 165 163
f 177 181 180
f 177 178 181
f 178 182 181
f 178 179 182
f 181 183 180
f 183 181 184
f 181 185 184
f 181 182 185
f 186 75 76
f 75 186 187
f 179 187 186
f 187 179 178
f 187 74 75
f 74 187 188
f 178 188 187
f 188 178 177
f 189 193 192
f 189 190 193
f 191 193 190
f 193 191 194
f 192 196 195
f 192 193 196
f 193 197 196
f 193 194 197
f 81 198 80
f 198 81 199
f 82 199 81
f 199 82 200
f 199 195 198
f 195 199 192
f 200 192 199
f 192 200 189
f 200 201 189
f 201 200 202
f 200 203 202
f 200 82 203
f 202 177 201
f 177 202 188
f 202 74 188
f 202 203 74
f 177 204 201
f 177 180 204
f 183 204 180
f 204 183 205
f 204 189 201
f 189 204 190
f 204 191 190
f 204 205 191
f 195 207 198
f 195 206 207
f 179 207 206
f 207 179 186
f 198 208 80
f 198 207 208
f 186 208 207
f 208 186 76
f 206 182 179
f 182 206 209
f 206 196 209
f 206 195 196
f 209 185 182
f 185 209 210
f 209 197 210
f 209 196 197
f 211 215 214
f 211 212 215
f 213 215 212
f 215 213 216
f 215 217 214
f 217 215 218
f 216 218 215
f 218 216 219
f 220 216 213
f 216 220 221
f 76 221 220
f 221 76 87
f 221 219 216
f 219 221 222
f 87 222 221
f 222 87 89
f 223 227 226
f 223 224 227
f 225 227 224
f 227 225 228
f 227 229 226
f 229 227 230
f 228 230 227
f 230 228 231
f 230 232 229
f 232 230 233
f 231 233 230
f 233 231 234
f 233 80 232
f 80 233 83
f 233 84 83
f 233 234 84
f 222 235 219
f 235 222 236
f 222 237 236
f 222 89 237
f 236 231 235
f 231 236 234
f 237 234 236
f 234 237 84
f 217 239 238
f 217 218 239
f 219 239 218
f 239 219 235
f 239 225 238
f 225 239 228
f 239 231 228
f 239 235 231
f 220 208 76
f 208 220 240
f 213 240 220
f 240 213 241
f 208 232 80
f 208 240 232
f 240 229 232
f 240 241 229
f 241 226 229
f 226 241 242
f 241 212 242
f 241 213 212
f 242 223 226
f 223 242 243
f 242 211 243
f 242 212 211
f 244 248 247
f 244 245 248
f 246 248 245
f 248 246 249
f 248 250 247
f 250 248 251
f 249 251 248
f 251 249 252
f 250 254 253
f 250 251 254
f 252 254 251
f 254 252 255
f 253 91 93
f 253 254 91
f 254 89 91
f 254 255 89
f 256 260 259
f 256 257 260
f 258 260 257
f 260 258 261
f 260 262 259
f 262 260 263
f 260 264 263
f 260 261 264
f 97 265 95
f 265 97 266
f 84 266 97
f 266 84 267
f 265 257 256
f 265 266 257
f 267 257 266
f 257 267 258
f 249 268 252
f 268 249 269
f 249 270 269
f 249 246 270
f 269 258 268
f 258 269 261
f 269 264 261
f 269 270 264
f 255 237 89
f 237 255 271
f 252 271 255
f 271 252 268
f 271 84 237
f 84 271 267
f 268 267 271
f 267 268 258
f 102 253 93
f 253 102 272
f 102 265 272
f 102 95 265
f 272 250 253
f 250 272 273
f 272 256 273
f 272 265 256
f 259 273 256
f 273 259 274
f 262 274 259
f 274 262 275
f 273 247 250
f 273 274 247
f 274 244 247
f 274 275 244
f 172 159 158
f 159 172 276
f 172 170 276
f 172 168 170
f 276 109 159
f 109 276 143
f 170 143 276
f 143 170 125
f 151 154 119
f 154 151 277
f 151 166 277
f 151 139 166
f 154 175 157
f 154 277 175
f 277 167 175
f 277 166 167
f 197 278 210
f 197 194 278
f 191 278 194
f 278 191 205
f 278 185 210
f 185 278 184
f 278 183 184
f 278 205 183
f 223 279 224
f 223 243 279
f 211 279 243
f 279 211 214
f 279 225 224
f 225 279 238
f 279 217 238
f 279 214 217
f 262 280 275
f 262 263 280
f 264 280 263
f 280 264 270
f 280 244 275
f 244 280 245
f 270 245 280
f 245 270 246
f 74 281 71
f 74 203 281
f 82 281 203
f 281 82 79
f 71 149 61
f 71 281 149
f 79 149 281
f 149 79 51
# 552 elements


*/





Renders a PointArray in Immediate Mode and outputs the FPS

/**********************************************************
 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.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.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.GraphicsContext3D;
import javax.media.j3d.Group;
import javax.media.j3d.Light;
import javax.media.j3d.Locale;
import javax.media.j3d.Material;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PointArray;
import javax.media.j3d.PointAttributes;
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.Point3f;
import javax.vecmath.Vector3d;
import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.utils.applet.MainFrame;
/**
 * This example renders a PointArray in Immediate Mode and outputs the FPS for
 * the rendering.
 * 
 * @see ImmediateCanvas3D.java for the rendering code.
 */
public class ImmediateTest extends Java3dApplet {
  private static int m_kWidth = 400;
  private static int m_kHeight = 400;
  public ImmediateTest() {
    // we need to create the minimal Java 3D scenegraph
    // structure to the View rendering loop.
    // create the VirtualUniverse
    m_Universe = createVirtualUniverse();
    // create a Locale
    Locale locale = createLocale(m_Universe);
    // create the ViewPlatform and add to the Locale
    ViewPlatform vp = createViewPlatform();
    BranchGroup viewBranchGroup = createViewBranchGroup(null, vp);
    addViewBranchGroup(locale, viewBranchGroup);
    // create the View and attach to the ViewPlatform
    createView(vp);
  }
  protected Canvas3D createCanvas3D() {
    // overidden this method to create a custom
    // Canvas3D that will implement the Immediate Mode rendering
    GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
    gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
    GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
        .getScreenDevices();
    ImmediateCanvas3D c3d = new ImmediateCanvas3D(gd[0]
        .getBestConfiguration(gc3D));
    c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
    return (Canvas3D) c3d;
  }
  public static void main(String[] args) {
    ImmediateTest immediateTest = new ImmediateTest();
    immediateTest.saveCommandLineArguments(args);
    new MainFrame(immediateTest, m_kWidth, m_kHeight);
  }
}
class ImmediateCanvas3D extends Canvas3D {
  private long m_nRender = 0;
  private long m_StartTime = 0;
  private static final int nGridSize = 50;
  private static final int m_kReportInterval = 50;
  private PointArray m_PointArray = new PointArray(nGridSize * nGridSize,
      GeometryArray.COORDINATES);
  private Transform3D m_t3d = new Transform3D();
  private float m_rot = 0.0f;
  ImmediateCanvas3D(java.awt.GraphicsConfiguration graphicsConfiguration) {
    super(graphicsConfiguration);
    // create the PointArray that we will be rendering
    int nPoint = 0;
    for (int n = 0; n < nGridSize; n++) {
      for (int i = 0; i < nGridSize; i++) {
        Point3f point = new Point3f(n - nGridSize / 2, i - nGridSize
            / 2, 0.0f);
        m_PointArray.setCoordinate(nPoint++, point);
      }
    }
  }
  public void renderField(int fieldDesc) {
    super.renderField(fieldDesc);
    GraphicsContext3D g = getGraphicsContext3D();
    // first time initialization
    if (m_nRender == 0) {
      // set the start time
      m_StartTime = System.currentTimeMillis();
      // add a light to the graphics context
      DirectionalLight light = new DirectionalLight();
      light.setEnable(true);
      g.addLight((Light) light);
      // create the material for the points
      Appearance a = new Appearance();
      Material mat = new Material();
      mat.setLightingEnable(true);
      mat.setAmbientColor(0.5f, 1.0f, 1.0f);
      a.setMaterial(mat);
      a.setColoringAttributes(new ColoringAttributes(1.0f, 0.5f, 0.5f,
          ColoringAttributes.NICEST));
      // enlarge the points
      a.setPointAttributes(new PointAttributes(4, true));
      // make the appearance current in the graphics context
      g.setAppearance(a);
    }
    // set the current transformation for the graphics context
    g.setModelTransform(m_t3d);
    // finally render the PointArray
    g.draw(m_PointArray);
    // calculate and display the Frames Per Second for the
    // Immediate Mode rendering of the PointArray
    m_nRender++;
    if ((m_nRender % m_kReportInterval) == 0) {
      float fps = (float) 1000.0f
          / ((System.currentTimeMillis() - m_StartTime) / (float) m_kReportInterval);
      System.out.println("FPS:\t" + fps);
      m_StartTime = System.currentTimeMillis();
    }
  }
  public void preRender() {
    super.preRender();
    // update the model transformation to rotate the PointArray
    // about the Y axis.
    m_rot += 0.1;
    m_t3d.rotY(m_rot);
    // move the transform back so we can see the points
    m_t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
    // scale the transformation down so we can see all of the points
    m_t3d.setScale(0.3);
    // force a paint (will call renderField)
    paint(getGraphics());
  }
}
/*******************************************************************************
 * 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;
  }
}