Java/3D/Alpha

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

Creates a scene which plots a custom Alpha function

/**********************************************************
 Copyright (C) 2001   Daniel Selman
 First distributed with the book "Java 3D Programming"
 by Daniel Selman and published by Manning Publications.
 http://manning.ru/selman
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation, version 2.
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 The license can be found on the WWW at:
 http://www.fsf.org/copyleft/gpl.html
 Or by writing to:
 Free Software Foundation, Inc.,
 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 Authors can be contacted at:
 Daniel Selman: daniel@selman.org
 If you make changes you think others would like, please 
 contact one of the authors or someone at the 
 www.j3d.org web site.
 **************************************************************/
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Vector;
import javax.media.j3d.Alpha;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.Locale;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PositionInterpolator;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
/**
 * Creates a scene which plots a custom Alpha function (loaded from a file). In
 * addition the Alpha is applied to a rendered object in a scene. Note: this
 * example does not currently run as an Applet.
 */
public class CustomAlphaTest extends Java3dApplet implements ActionListener,
    FileAlphaListener {
  private static int m_kWidth = 600;
  private static int m_kHeight = 600;
  final int m_knLoopCount = 0;
  final long m_kTimeStep = 200;
  private FileAlpha m_Alpha = null;
  private Vector m_EditFieldVector = null;
  private BufferedImage m_Image = null;
  private long m_CurrentTime = 0;
  private float m_CurrentValue = 0;
  // offsets and drawing information
  private int m_nMaxHeight = 0;
  private int m_nMaxWidth = 0;
  private int m_nInsetX = 0;
  private int m_nInsetY = 0;
  private int m_nGraphMaxWidth = 0;
  private int m_nGraphMaxHeight = 0;
  private int m_nGraphInsetX = 0;
  private int m_nGraphInsetY = 0;
  private double m_ScaleX = 0;
  public CustomAlphaTest() {
    try {
      // HACK:
      // if we are running as an Applet
      // the getWorkingDirectory() call will throw an NPE
      // as we cannot call getCodeBase until "start" has been called
      // (below).
      m_Alpha = new FileAlpha(
          new URL(getWorkingDirectory(), "values.xls"));
      m_Image = new BufferedImage(m_kWidth, m_kHeight,
          BufferedImage.TYPE_INT_RGB);
      buildUi();
      initJava3d();
    } catch (Exception e) {
    }
  }
  // we duplicate this code here for Applet support
  public void start() {
    if (m_Alpha != null)
      return;
    try {
      m_Alpha = new FileAlpha(
          new URL(getWorkingDirectory(), "values.xls"));
      m_Image = new BufferedImage(m_kWidth, m_kHeight,
          BufferedImage.TYPE_INT_RGB);
      buildUi();
      initJava3d();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  protected void addCanvas3D(Canvas3D c3d) {
    Frame frame = new Frame("Custom Alpha Test");
    Panel aPanel = new Panel();
    aPanel.setLayout(new BorderLayout());
    aPanel.add(c3d, BorderLayout.CENTER);
    frame.add(aPanel);
    frame.pack();
    frame.setSize(new Dimension(320, 320));
    frame.validate();
    frame.setVisible(true);
    doLayout();
  }
  protected void buildUi() {
    m_EditFieldVector = new Vector(1);
    addField("Loop Count", m_knLoopCount);
    addButton("Update");
    updateUi();
    drawGraph();
    repaint();
  }
  protected BranchGroup createSceneBranchGroup() {
    BranchGroup objRoot = super.createSceneBranchGroup();
    TransformGroup objTrans = new TransformGroup();
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    ColorCube cube = new ColorCube(2);
    objTrans.addChild(cube);
    FileAlpha fileAlpha = null;
    try {
      fileAlpha = new FileAlpha(new URL(getWorkingDirectory(),
          "values.xls"), this);
    } catch (Exception e) {
      e.toString();
    }
    PositionInterpolator posInterpolator = new PositionInterpolator(
        fileAlpha, objTrans, new Transform3D(), -6, 6);
    posInterpolator.setSchedulingBounds(getApplicationBounds());
    objTrans.addChild(posInterpolator);
    objRoot.addChild(objTrans);
    return objRoot;
  }
  // handle event from the GUI components we created
  public void actionPerformed(ActionEvent event) {
    if (event.getActionCommand().equals("Update") != false) {
      updateAlpha();
      updateUi();
      drawGraph();
      repaint();
    }
  }
  protected void updateAlpha() {
    if (m_Alpha != null)
      m_Alpha.setLoopCount(Integer.parseInt(getField(m_knLoopCount)
          .getText()));
  }
  protected void updateUi() {
    if (m_Alpha != null)
      getField(m_knLoopCount).setText(
          String.valueOf(m_Alpha.getLoopCount()));
  }
  long getMaxTime() {
    return m_Alpha.getStopTime();
  }
  protected void drawGraph() {
    if (m_Alpha != null) {
      Graphics g = m_Image.getGraphics();
      g.setColor(Color.white);
      g.fillRect(0, 0, m_kWidth, m_kHeight);
      g.setColor(Color.black);
      m_Alpha.setStartTime(0);
      long lMaxTime = getMaxTime();
      computeDrawScale(lMaxTime);
      drawAxes(g, lMaxTime);
      drawPhases(g, lMaxTime);
      drawAlpha(g, lMaxTime);
    }
  }
  protected TextField getField(final int nIndex) {
    return (TextField) m_EditFieldVector.get(nIndex);
  }
  protected void addButton(final String szText) {
    Button button = new Button(szText);
    button.addActionListener(this);
    add(button);
  }
  protected void addField(final String szText, final int nIndex) {
    Label label = new Label(szText);
    TextField textField = new TextField(4);
    m_EditFieldVector.add(nIndex, (Object) textField);
    add(label);
    add(textField);
  }
  protected void computeDrawScale(long lMaxTime) {
    int nWidth = getWidth();
    int nHeight = getHeight();
    if (nWidth > m_kWidth)
      nWidth = m_kWidth;
    if (nHeight > m_kHeight)
      nHeight = m_kHeight;
    m_nMaxHeight = (int) (nHeight * 0.7);
    m_nMaxWidth = (int) (nWidth * 0.9);
    m_nInsetX = (nWidth - m_nMaxWidth) / 2;
    m_nInsetY = (int) ((nHeight - m_nMaxHeight) / 1.1);
    m_nGraphMaxWidth = (int) (m_nMaxWidth * 0.80);
    m_nGraphMaxHeight = (int) (m_nMaxHeight * 0.80);
    m_nGraphInsetX = (m_nMaxWidth - m_nGraphMaxWidth) / 2;
    m_nGraphInsetY = (m_nMaxHeight - m_nGraphMaxHeight) / 2;
    m_ScaleX = ((double) m_nGraphMaxWidth) / ((double) lMaxTime);
  }
  protected void drawAreaRect(Graphics g, int x, int y, int width, int height) {
    g.drawRect(x, y, width, height);
  }
  protected void drawAreaString(Graphics g, int nLen, String szText,
      double x, double y) {
    if (nLen > 0 && szText.length() > nLen)
      szText = szText.substring(0, nLen);
    g.drawString(szText, (int) x, (int) (m_nMaxHeight - y));
  }
  protected void drawGraphString(Graphics g, int nLen, String szText,
      double x, double y) {
    if (nLen > 0 && szText.length() > nLen)
      szText = szText.substring(0, nLen);
    g.drawString(szText, (int) (m_nGraphInsetX + x), (int) (m_nGraphInsetY
        + m_nGraphMaxHeight - y));
  }
  protected void drawGraphLine(Graphics g, double x1, double y1, double x2,
      double y2) {
    g.drawLine((int) (m_nGraphInsetX + x1), (int) (m_nGraphInsetY
        + m_nGraphMaxHeight - y1), (int) (m_nGraphInsetX + x2),
        (int) (m_nGraphInsetY + m_nGraphMaxHeight - y2));
  }
  protected void drawGraphFillCircle(Graphics g, double x1, double y1,
      double radius) {
    g.fillOval((int) (m_nGraphInsetX + x1 - radius), (int) (m_nGraphInsetY
        + m_nGraphMaxHeight - y1 - radius), (int) (radius * 2),
        (int) (radius * 2));
  }
  protected void drawAxes(Graphics g, long lMaxTime) {
    // draw the frame
    drawAreaRect(g, 0, 0, m_nMaxWidth, m_nMaxHeight);
    drawGraphString(g, -1, "Alpha vs. Time (secs)", m_nGraphMaxWidth / 2,
        m_nGraphMaxHeight + 20);
    // draw the X axis
    drawGraphLine(g, 0, 0, m_nGraphMaxWidth, 0);
    // draw the Y axis
    drawGraphLine(g, 0, 0, 0, m_nGraphMaxHeight);
    // draw the horizontal Y axis lines
    for (double yAxisTick = 0; yAxisTick <= 1.0; yAxisTick += 0.2) {
      double yTick = yAxisTick * m_nGraphMaxHeight;
      g.setColor(Color.gray);
      drawGraphLine(g, 0, yTick, m_nGraphMaxWidth, yTick);
      g.setColor(Color.black);
      drawGraphString(g, 3, "" + yAxisTick, -20, yTick);
    }
  }
  protected void drawPhases(Graphics g, long lMaxTime) {
    double curTime = 0;
    g.setColor(Color.darkGray);
    int nLoop = 1;
    if (m_Alpha.getLoopCount() > 0)
      nLoop = m_Alpha.getLoopCount();
    for (int n = 0; n < nLoop; n++) {
      for (int nValue = 0; nValue < m_Alpha.getNumValues(); nValue++) {
        curTime = n * m_Alpha.getMaxTime()
            + m_Alpha.getTimeForValue(nValue);
        g.setColor(Color.black);
        drawGraphString(g, -1, "" + (curTime / 1000), curTime
            * m_ScaleX, -20);
        g.setColor(Color.darkGray);
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
      }
    }
    g.setColor(Color.black);
  }
  protected void drawAlpha(Graphics g, long lMaxTime) {
    g.setColor(Color.blue);
    float value = 0;
    double x1 = 0;
    double y1 = 0;
    double x2 = 0;
    double y2 = 0;
    for (long lTime = 0; lTime <= lMaxTime; lTime += m_kTimeStep) {
      value = m_Alpha.value(lTime);
      x2 = lTime * m_ScaleX;
      y2 = value * m_nGraphMaxHeight;
      drawGraphLine(g, x1, y1, x2, y2);
      x1 = x2;
      y1 = y2;
    }
    g.setColor(Color.black);
  }
  protected void drawCurrentPosition(Graphics g) {
    drawGraphFillCircle(g, m_nInsetX + m_CurrentTime * m_ScaleX,
        m_CurrentValue * m_nGraphMaxHeight - m_nInsetY, 3);
  }
  public void onFileAlphaGetValue(long ltime, float value) {
    m_CurrentTime = ltime % m_Alpha.getStopTime();
    m_CurrentValue = value;
    int repaintX = (int) (m_nGraphInsetX + m_nInsetX + m_CurrentTime
        * m_ScaleX);
    int repaintY = (int) (m_nGraphInsetY + m_nGraphMaxHeight - (m_CurrentValue
        * m_nGraphMaxHeight - m_nInsetY));
    Graphics g = getGraphics();
    if (g != null) {
      repaint(repaintX - 5, repaintY - 5, 10, 10);
      drawCurrentPosition(g);
    }
  }
  public void paint(Graphics g) {
    super.paint(g);
    if (m_Alpha != null) {
      drawGraph();
      g.drawImage(m_Image, m_nInsetX, m_nInsetY, this);
    }
  }
  public static void main(String[] args) {
    CustomAlphaTest alphaTest = new CustomAlphaTest();
    new MainFrame(alphaTest, m_kWidth, m_kHeight);
  }
}
//this class defines an Alpha class that reads time/alpha
//value pairs from a file and linearly interpolates between
//them. It illustrates creating your own Alpha class for
//interpolation.
class FileAlpha extends Alpha {
  // store a Vector of AlphaPairs that define
  // the Alpha value for each time
  protected Vector m_AlphaVector = null;
  // we override tracking of start and stop time
  protected long m_StartTime = 0;
  protected long m_StopTime = 0;
  // we override tracking of loop count
  protected int m_nLoopCount = -1;
  protected FileAlphaListener m_Listener = null;
  public FileAlpha(URL url) {
    this(url, null);
  }
  public FileAlpha(URL url, FileAlphaListener listener) {
    m_Listener = listener;
    // create the vector used to store the AlphaPairs
    m_AlphaVector = new Vector();
    // read the AlphaPairs from the text file
    readAlphaValues(url);
    System.out.println("Read " + getNumValues() + " Alpha pairs.");
    // initialize the start/stop times
    m_StartTime = System.currentTimeMillis();
    m_StopTime = m_StartTime + getMaxTime();
  }
  // this method is overriden to update the stop time
  public void setStartTime(long l) {
    m_StartTime = l;
    if (m_nLoopCount > 0)
      m_StopTime = m_StartTime + m_nLoopCount * getMaxTime();
    else
      m_StopTime = m_StartTime + getMaxTime();
  }
  // overriden to return our member variable
  public long getStartTime() {
    return m_StartTime;
  }
  public long getStopTime() {
    return m_StopTime;
  }
  // overriden to update the stop time
  public void setLoopCount(int i) {
    m_nLoopCount = i;
    if (m_nLoopCount > 0)
      m_StopTime = m_StartTime + i * getMaxTime();
    else
      m_StopTime = m_StartTime + getMaxTime();
  }
  // overriden to return our member variable
  public int getLoopCount() {
    return m_nLoopCount;
  }
  // overriden to use our member variables
  public boolean finished() {
    if (m_nLoopCount == -1)
      return false;
    return (System.currentTimeMillis() - m_StartTime > m_StopTime);
  }
  // core method override
  // returns the Alpha value for a given time
  public float value(long time) {
    if (time >= m_StartTime)
      return valueFromStart(time - m_StartTime);
    return 0;
  }
  // helper method to retrieve the AlphaPair
  // to the left and right of the time and
  // linearly interpolate between them.
  //
  // Note: this method could be optimized!
  protected float valueFromStart(long time) {
    long modTime = time;
    float value = 0;
    if (time > getMaxTime() && getMaxTime() > 0)
      modTime = time % getMaxTime();
    AlphaPair leftPair = getLeftPairFromTime(modTime);
    AlphaPair rightPair = getRightPairFromTime(modTime);
    if (leftPair != null && rightPair != null) {
      float deltaAlpha = rightPair.getAlpha() - leftPair.getAlpha();
      long deltaTime = rightPair.getTime() - leftPair.getTime();
      float slope = 0;
      if (deltaTime != 0)
        slope = deltaAlpha / deltaTime;
      long subTime = modTime - leftPair.getTime();
      value = leftPair.getAlpha() + subTime * slope;
      if (m_Listener != null)
        m_Listener.onFileAlphaGetValue(time, value);
    }
    return value;
  }
  // returns the AlphaPair for a given index
  protected AlphaPair getAlphaPairForIndex(int nIndex) {
    if (nIndex < 0 || nIndex >= m_AlphaVector.size())
      return null;
    return (AlphaPair) m_AlphaVector.get(nIndex);
  }
  // returns an AlphaPair immediately to the
  // left of the given time
  protected AlphaPair getLeftPairFromTime(long time) {
    AlphaPair alphaPair = null;
    for (int nIndex = 0; nIndex < getNumValues(); nIndex++) {
      alphaPair = getAlphaPairForIndex(nIndex);
      if (alphaPair != null) {
        if (alphaPair.getTime() == time)
          return alphaPair;
        if (alphaPair.getTime() > time) {
          if (nIndex > 0)
            return getAlphaPairForIndex(nIndex - 1);
          else
            break;
        }
      }
    }
    return alphaPair;
  }
  // returns an AlphaPair immediately to the
  // right of the given time
  protected AlphaPair getRightPairFromTime(long time) {
    AlphaPair alphaPair = null;
    for (int nIndex = 0; nIndex < getNumValues(); nIndex++) {
      alphaPair = getAlphaPairForIndex(nIndex);
      if (alphaPair != null && alphaPair.getTime() >= time)
        return alphaPair;
    }
    return alphaPair;
  }
  // returns the number of AlphaPairs loaded
  public int getNumValues() {
    return m_AlphaVector.size();
  }
  // returns the time for the AlphaPair at
  // a given index
  public long getTimeForValue(int nIndex) {
    AlphaPair alphaPair = getAlphaPairForIndex(nIndex);
    if (alphaPair != null) {
      return getAlphaPairForIndex(nIndex).getTime();
    }
    return 0;
  }
  // returns the maximum loaded AlphaPair time
  public long getMaxTime() {
    return getTimeForValue(getNumValues() - 1);
  }
  // read the AlphaPairs from a file.
  protected void readAlphaValues(URL url) {
    // allocate a temporary buffer to store the input file
    StringBuffer szBufferData = new StringBuffer();
    try {
      InputStream inputStream = url.openStream();
      int nChar = 0;
      // read the entire file into the StringBuffer
      while (true) {
        nChar = inputStream.read();
        // if we have not hit the end of file
        // add the character to the StringBuffer
        if (nChar != -1)
          szBufferData.append((char) nChar);
        else
          // EOF
          break;
      }
      inputStream.close();
      // create a tokenizer to tokenize the input file at whitespace
      java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
          szBufferData.toString());
      // keep reading time/alpha pairs until we hit EOF
      while (true) {
        try {
          long time = Long.parseLong(tokenizer.nextToken());
          float alpha = Float.parseFloat(tokenizer.nextToken());
          m_AlphaVector.add(new AlphaPair(time, alpha));
        } catch (Exception e) {
          break;
        }
      }
    } catch (Exception e) {
      System.err.println(e.toString());
    }
  }
}
interface FileAlphaListener {
  public void onFileAlphaGetValue(long ltime, float value);
}
class AlphaPair {
  private long m_Time = 0;
  private float m_Alpha = 0;
  public AlphaPair(long time, float alpha) {
    m_Time = time;
    m_Alpha = alpha;
  }
  public float getAlpha() {
    return m_Alpha;
  }
  public long getTime() {
    return m_Time;
  }
}
/*******************************************************************************
 * 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;
  }
}





Draws a simple plot of a parameterized Java 3D Alpha Function to an AWT

/**********************************************************
 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
 Lee Dixon:     leedixon@email.ru
 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.Button;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.media.j3d.Alpha;
import com.sun.j3d.utils.applet.MainFrame;
/**
 * Draws a simple plot of a parameterized Java 3D Alpha Function to an AWT
 * Window.
 */
public class AlphaTest extends Applet implements ActionListener {
  /**
   * default size of the window
   */
  private static int m_kWidth = 400;
  private static int m_kHeight = 400;
  /**
   * indexes into the UI components we create
   */
  private static final int m_knTrigger = 0;
  private static final int m_knPhaseDelay = 1;
  private static final int m_knIncreasingAlpha = 2;
  private static final int m_knIncreasingRamp = 3;
  private static final int m_knAtOne = 4;
  private static final int m_knDecreasingAlpha = 5;
  private static final int m_knDecreasingRamp = 6;
  private static final int m_knAtZero = 7;
  private static final int m_knLoopCount = 8;
  /**
   * controls how smooth a plot curve we create
   */
  private final static long m_kTimeStep = 10;
  /**
   * the Java 3D Alpha object we are parameterizing
   */
  private Alpha m_Alpha = null;
  /**
   * a Vector of Edit UI components
   */
  Vector m_EditFieldVector = null;
  /**
   * offsets and drawing information
   */
  int m_nMaxHeight = 0;
  int m_nMaxWidth = 0;
  int m_nInsetX = 0;
  int m_nInsetY = 0;
  int m_nGraphMaxWidth = 0;
  int m_nGraphMaxHeight = 0;
  int m_nGraphInsetX = 0;
  int m_nGraphInsetY = 0;
  double m_ScaleX = 0;
  /**
   * CheckboxGroup for INCREASING/DECREASING PHASE enable
   */
  private CheckboxGroup m_checkboxGrp;
  /**
   * Constructor
   */
  public AlphaTest() {
    m_Alpha = new Alpha(-1, Alpha.DECREASING_ENABLE
        | Alpha.INCREASING_ENABLE, 1000, 1000, 5000, 1000, 1000, 10000,
        2000, 4000);
    buildUi();
  }
  /**
   * Creates the UI components
   */
  protected void buildUi() {
    m_EditFieldVector = new Vector(10);
    addField("Trigger Time", m_knTrigger);
    addField("Phase Delay", m_knPhaseDelay);
    addField("Increasing Alpha", m_knIncreasingAlpha);
    addField("Increasing Ramp", m_knIncreasingRamp);
    addField("At One", m_knAtOne);
    addField("Decreasing Alpha", m_knDecreasingAlpha);
    addField("Decreasing Ramp", m_knDecreasingRamp);
    addField("At Zero", m_knAtZero);
    addField("Loop Count", m_knLoopCount);
    m_checkboxGrp = new CheckboxGroup();
    add(new Checkbox("INCREASING_ENABLE", m_checkboxGrp, false));
    add(new Checkbox("DECREASING_ENABLE", m_checkboxGrp, false));
    add(new Checkbox("BOTH", m_checkboxGrp, true));
    addButton("Update");
    updateUi();
  }
  /**
   * Handle events from the GUI components we created
   */
  public void actionPerformed(ActionEvent event) {
    if (event.getActionCommand().equals("Update") != false) {
      updateAlpha();
      repaint();
    }
  }
  /**
   * Replots the Alpha function based on the contents of the UI
   */
  protected void updateAlpha() {
    m_Alpha.setTriggerTime(Long.parseLong(getField(m_knTrigger).getText()));
    m_Alpha.setPhaseDelayDuration(Long.parseLong(getField(m_knPhaseDelay)
        .getText()));
    m_Alpha.setIncreasingAlphaDuration(Long.parseLong(getField(
        m_knIncreasingAlpha).getText()));
    m_Alpha.setIncreasingAlphaRampDuration(Long.parseLong(getField(
        m_knIncreasingRamp).getText()));
    m_Alpha.setAlphaAtOneDuration(Long.parseLong(getField(m_knAtOne)
        .getText()));
    m_Alpha.setDecreasingAlphaDuration(Long.parseLong(getField(
        m_knDecreasingAlpha).getText()));
    m_Alpha.setDecreasingAlphaRampDuration(Long.parseLong(getField(
        m_knDecreasingRamp).getText()));
    m_Alpha.setAlphaAtZeroDuration(Long.parseLong(getField(m_knAtZero)
        .getText()));
    m_Alpha.setLoopCount(Integer
        .parseInt(getField(m_knLoopCount).getText()));
    Checkbox b = m_checkboxGrp.getSelectedCheckbox();
    if (b.getLabel().equals("INCREASING_ENABLE")) {
      m_Alpha.setMode(Alpha.INCREASING_ENABLE);
    } else if (b.getLabel().equals("DECREASING_ENABLE")) {
      m_Alpha.setMode(Alpha.DECREASING_ENABLE);
    } else // "BOTH"
    {
      m_Alpha.setMode(Alpha.INCREASING_ENABLE | Alpha.DECREASING_ENABLE);
    }
  }
  /**
   * Updates the UI based on the Alpha function
   */
  protected void updateUi() {
    getField(m_knTrigger).setText(String.valueOf(m_Alpha.getTriggerTime()));
    getField(m_knPhaseDelay).setText(
        String.valueOf(m_Alpha.getPhaseDelayDuration()));
    getField(m_knIncreasingAlpha).setText(
        String.valueOf(m_Alpha.getIncreasingAlphaDuration()));
    getField(m_knIncreasingRamp).setText(
        String.valueOf(m_Alpha.getIncreasingAlphaRampDuration()));
    getField(m_knAtOne).setText(
        String.valueOf(m_Alpha.getAlphaAtOneDuration()));
    getField(m_knDecreasingAlpha).setText(
        String.valueOf(m_Alpha.getDecreasingAlphaDuration()));
    getField(m_knDecreasingRamp).setText(
        String.valueOf(m_Alpha.getDecreasingAlphaRampDuration()));
    getField(m_knAtZero).setText(
        String.valueOf(m_Alpha.getAlphaAtZeroDuration()));
    getField(m_knLoopCount).setText(String.valueOf(m_Alpha.getLoopCount()));
  }
  /**
   * Helper method to add a TextField to the UI
   */
  protected void addField(final String szText, final int nIndex) {
    Label label = new Label(szText);
    TextField textField = new TextField(4);
    m_EditFieldVector.add(nIndex, (Object) textField);
    add(label);
    add(textField);
  }
  /**
   * Retrieves a TextField with a given index
   */
  protected TextField getField(final int nIndex) {
    return (TextField) m_EditFieldVector.get(nIndex);
  }
  /**
   * Helper method to add a Button to the UI.
   */
  protected void addButton(final String szText) {
    Button button = new Button(szText);
    button.addActionListener(this);
    add(button);
  }
  /**
   * Computes the drawing scales based on the Alpha function and the size of
   * the Window.
   */
  protected void computeDrawScale(long lMaxTime) {
    m_nMaxHeight = (int) (getHeight() * 0.7);
    m_nMaxWidth = (int) (getWidth() * 0.9);
    m_nInsetX = (getWidth() - m_nMaxWidth) / 2;
    m_nInsetY = (int) ((getHeight() - m_nMaxHeight) / 1.1);
    m_nGraphMaxWidth = (int) (m_nMaxWidth * 0.80);
    m_nGraphMaxHeight = (int) (m_nMaxHeight * 0.80);
    m_nGraphInsetX = m_nInsetX + (m_nMaxWidth - m_nGraphMaxWidth) / 2;
    m_nGraphInsetY = m_nInsetY + (m_nMaxHeight - m_nGraphMaxHeight) / 2;
    m_ScaleX = ((double) m_nGraphMaxWidth) / ((double) lMaxTime);
  }
  /**
   * Draws a rectangle into the display area for the plot.
   */
  protected void drawAreaRect(Graphics g, int x, int y, int width, int height) {
    g.drawRect(m_nInsetX + x, m_nInsetY + y, width, height);
  }
  /**
   * Draws a String into the display area for the plot.
   */
  protected void drawAreaString(Graphics g, int nLen, String szText,
      double x, double y) {
    if (nLen > 0 && szText.length() > nLen)
      szText = szText.substring(0, nLen);
    g.drawString(szText, (int) (m_nInsetX + x), (int) (m_nMaxHeight
        + m_nInsetY - y));
  }
  /**
   * Draws a String into the graph area for the plot.
   */
  protected void drawGraphString(Graphics g, int nLen, String szText,
      double x, double y) {
    if (nLen > 0 && szText.length() > nLen)
      szText = szText.substring(0, nLen);
    g.drawString(szText, (int) (m_nGraphInsetX + x), (int) (m_nGraphInsetY
        + m_nGraphMaxHeight - y));
  }
  /**
   * Draws a Line into the graph area for the plot.
   */
  protected void drawGraphLine(Graphics g, double x1, double y1, double x2,
      double y2) {
    g.drawLine((int) (m_nGraphInsetX + x1), (int) (m_nGraphInsetY
        + m_nGraphMaxHeight - y1), (int) (m_nGraphInsetX + x2),
        (int) (m_nGraphInsetY + m_nGraphMaxHeight - y2));
  }
  /**
   * Draws the axes for the graph.
   */
  protected void drawAxes(Graphics g, long lMaxTime) {
    drawGraphString(g, -1, "Alpha vs. Time (ms)", m_nGraphMaxWidth / 2,
        m_nGraphMaxHeight + 20);
    // draw the frame
    drawAreaRect(g, 0, 0, m_nMaxWidth, m_nMaxHeight);
    // draw the X axis
    drawGraphLine(g, 0, 0, m_nGraphMaxWidth, 0);
    // draw the Y axis
    drawGraphLine(g, 0, 0, 0, m_nGraphMaxHeight);
    // draw the horizontal Y axis lines
    for (double yAxisTick = 0; yAxisTick <= 1.0; yAxisTick += 0.2) {
      double yTick = yAxisTick * m_nGraphMaxHeight;
      g.setColor(Color.gray);
      drawGraphLine(g, 0, yTick, m_nGraphMaxWidth, yTick);
      g.setColor(Color.black);
      drawGraphString(g, 3, "" + yAxisTick, -20, yTick);
    }
  }
  /**
   * Draws vertical lines and labels to denote the various phases of the Alpha
   * function.
   */
  protected void drawPhases(Graphics g, long lMaxTime) {
    int nLoop = 1;
    if (m_Alpha.getLoopCount() > 0)
      nLoop = m_Alpha.getLoopCount();
    double curTime = 0;
    g.setColor(Color.darkGray);
    curTime += m_Alpha.getTriggerTime();
    drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
        m_nGraphMaxHeight);
    curTime += m_Alpha.getPhaseDelayDuration();
    drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
        m_nGraphMaxHeight);
    double startPhaseTime = 0;
    for (int nIteration = 0; nIteration < nLoop; nIteration++) {
      startPhaseTime = curTime;
      g.setColor(Color.black);
      drawGraphString(g, -1, "" + curTime, curTime * m_ScaleX, -20);
      g.setColor(Color.darkGray);
      if ((m_Alpha.getMode() & Alpha.INCREASING_ENABLE) != 0) {
        curTime += m_Alpha.getIncreasingAlphaRampDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
        curTime = startPhaseTime + m_Alpha.getIncreasingAlphaDuration()
            - m_Alpha.getIncreasingAlphaRampDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
        curTime = startPhaseTime + m_Alpha.getIncreasingAlphaDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
        curTime += m_Alpha.getAlphaAtOneDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
      }
      startPhaseTime = curTime;
      if ((m_Alpha.getMode() & Alpha.DECREASING_ENABLE) != 0) {
        curTime += m_Alpha.getDecreasingAlphaRampDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
        curTime = startPhaseTime + m_Alpha.getDecreasingAlphaDuration()
            - m_Alpha.getDecreasingAlphaRampDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
        curTime = startPhaseTime + m_Alpha.getDecreasingAlphaDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
        curTime += m_Alpha.getAlphaAtZeroDuration();
        drawGraphLine(g, curTime * m_ScaleX, 0, curTime * m_ScaleX,
            m_nGraphMaxHeight);
      }
    }
    g.setColor(Color.black);
  }
  /**
   * Plots the Alpha function into the graph area of the plot.
   */
  protected void drawAlpha(Graphics g, long lMaxTime) {
    g.setColor(Color.blue);
    float value = 0;
    m_Alpha.setStartTime(0);
    double x1 = 0;
    double y1 = 0;
    double x2 = 0;
    double y2 = 0;
    for (long lTime = 0; lTime <= lMaxTime; lTime += m_kTimeStep) {
      value = m_Alpha.value(lTime);
      x2 = lTime * m_ScaleX;
      y2 = value * m_nGraphMaxHeight;
      drawGraphLine(g, x1, y1, x2, y2);
      x1 = x2;
      y1 = y2;
    }
    g.setColor(Color.black);
  }
  /**
   * AWT paint method that can handle dynamic scale recomputation and graph
   * redraw.
   */
  public void paint(Graphics g) {
    super.paint(g);
    long lMaxTime = 0;
    if ((m_Alpha.getMode() & Alpha.INCREASING_ENABLE) != 0) {
      lMaxTime += m_Alpha.getIncreasingAlphaDuration()
          + m_Alpha.getAlphaAtOneDuration();
    }
    if ((m_Alpha.getMode() & Alpha.DECREASING_ENABLE) != 0) {
      lMaxTime += m_Alpha.getDecreasingAlphaDuration()
          + m_Alpha.getAlphaAtZeroDuration();
    }
    if (m_Alpha.getLoopCount() > 0)
      lMaxTime *= m_Alpha.getLoopCount();
    lMaxTime += m_Alpha.getTriggerTime();
    lMaxTime += m_Alpha.getPhaseDelayDuration();
    computeDrawScale(lMaxTime);
    drawAxes(g, lMaxTime);
    drawPhases(g, lMaxTime);
    drawAlpha(g, lMaxTime);
  }
  /**
   * Simple main method that uses the Java 3D MainFrame helper class.
   */
  public static void main(String[] args) {
    AlphaTest alphaTest = new AlphaTest();
    new MainFrame(alphaTest, m_kWidth, m_kHeight);
  }
}