/*
 * Example program showing the slowdown that occurs with adding a
 * default PolygonAttributes to an appearance.  Toggle the
 * "runItSlow" variable below to see the problem.
 */
import java.applet.Applet;
import java.awt.event.*;
import javax.vecmath.*;
import javax.media.j3d.*;
import java.awt.*;

import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.ViewingPlatform;
import com.sun.j3d.utils.applet.MainFrame;


public class TestBed extends Applet
{
  // Change the variable 
  boolean runItSlow=false;

  static public void main(String[] args)
  {
        System.out.println("in main");
        new MainFrame(new TestBed(), 300, 300);
  }

  TestBed()
  {
    setLayout(new BorderLayout());

    // Make the canvas.  Use our derived canvas to compute frame rate.
    GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
    GraphicsConfiguration gcfg =
              GraphicsEnvironment.getLocalGraphicsEnvironment().
              getDefaultScreenDevice().getBestConfiguration(template);
    TestBedCanvas canvas = new TestBedCanvas(gcfg);
    canvas.setSize(300, 300);
    add("Center", canvas);

    // Create the universe.
    SimpleUniverse universe = new SimpleUniverse(canvas);

    // Create the main branch.
    BranchGroup mainBranch = new BranchGroup();

    // Make an array of rotating squares.
    float x, y;
    for(y=-7.0f; y<7.5f; y=y+2.0f)
      for(x=-7.0f; x<7.5f; x=x+2.0f)
        mainBranch.addChild(new RotatingSquare(x, y, runItSlow));

    // Make the main branch live.
    universe.addBranchGraph(mainBranch);
  }
}


class TestBedCanvas extends Canvas3D
{
  private long lastTime=-1;
  private long frameCount=0;

  TestBedCanvas(GraphicsConfiguration gcfg)
  {
        super(gcfg);
  }

  public void postRender()
  {
    super.postRender();
    frameCount++;

    long time=System.currentTimeMillis();
    if (lastTime==-1)
    {
      lastTime=time;
      return;
    }

    else
    {
      long elapsed = time-lastTime;
      if (elapsed >= 4000)
      {
        double fps = ((double)(frameCount) / (double)(elapsed)) * 1000.0;
        System.out.println("FPS: " + fps);
        frameCount=0;
        lastTime = time;
      }
    }

  }  // END postRender()

}


class RotatingSquare extends BranchGroup
{

  RotatingSquare(float cx, float cy, boolean runItSlow)
  {
  TransformGroup rotateGroup = new TransformGroup();
  rotateGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
  Transform3D local = new Transform3D();
  local.rotX(1.57); // this will move the axis of rotation from +Y to +Z axis
  local.setTranslation(new Vector3f(cx, cy, 0.0f));
  Alpha alpha = new Alpha(-1, 6000);
  RotationInterpolator rotint =
    new RotationInterpolator(alpha, rotateGroup,
                             local, 0.0f, 6.28f);
  rotint.setSchedulingBounds(
    new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 1000.0));

  Point3f[] coords = new Point3f[]
  {
    new Point3f(cx+-0.5f, cy+-0.5f, -20.0f),
    new Point3f(cx+ 0.5f, cy+-0.5f, -20.0f),
    new Point3f(cx+-0.5f, cy+ 0.5f, -20.0f),
    new Point3f(cx+ 0.5f, cy+ 0.5f, -20.0f)
  };
  int[] stripVertexCounts = new int[1];
  stripVertexCounts[0] = 4;
  TriangleStripArray groundGeom =
    new TriangleStripArray(4, GeometryArray.COORDINATES, stripVertexCounts);
  groundGeom.setCoordinates(0, coords);
  Appearance appearance = new Appearance();

  // THIS IS THE OFFENDING LINE WHICH BRINGS DOWN THE FRAME RATE
  if(runItSlow)
    appearance.setPolygonAttributes(new PolygonAttributes());

  Shape3D ground = new Shape3D(groundGeom, appearance);
  rotateGroup.addChild(ground);

  this.addChild(rotateGroup);
  this.addChild(rotint);

  }
}
