Java tutorial
/* * @(#)FPSCounterDemo.java 1.3 02/10/21 13:38:59 * * 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.text.NumberFormat; import javax.media.j3d.Alpha; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.WakeupOnElapsedFrames; import javax.swing.JOptionPane; import javax.vecmath.Point3d; import com.sun.j3d.utils.applet.JMainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.universe.SimpleUniverse; /** * This program demonstrates the use of the frames per second counter. The * program displays a rotating cube and sets up the FPSCounter to compute the * frame rate. The FPSCounter is set up with default values: - run indefinitely - * 2 sec. warmup time - display average frame rate every fifth sampling * interval. The default values can be changed through the command line * arguments. Use FPSCounterDemo -h for help on the various arguments. */ public class FPSCounterDemo extends Applet { private SimpleUniverse u = null; \private FPSCounter fpsCounter = new FPSCounter(); BranchGroup createSceneGraph() { // Create the root of the branch graph BranchGroup objRoot = new BranchGroup(); // Create the TransformGroup node and initialize it to the // identity. Enable the TRANSFORM_WRITE capability so that // our behavior code can modify it at run time. Add it to // the root of the subgraph. TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objRoot.addChild(objTrans); // Create a simple Shape3D node; add it to the scene graph. objTrans.addChild(new ColorCube(0.4)); // Create a new Behavior object that will perform the // desired operation on the specified transform and add // it into the scene graph. Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, 4000); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); rotator.setSchedulingBounds(bounds); objRoot.addChild(rotator); // Create the Framecounter behavior fpsCounter.setSchedulingBounds(bounds); objRoot.addChild(fpsCounter); return objRoot; } public FPSCounterDemo(String args[]) { } public FPSCounterDemo() { } public void init() { setLayout(new BorderLayout()); GraphicsConfiguration config = SimpleUniverse .getPreferredConfiguration(); Canvas3D c = new Canvas3D(config); add("Center", c); // Create a simple scene and attach it to the virtual universe BranchGroup scene = createSceneGraph(); // Parse the command line to set the various parameters // Have Java 3D perform optimizations on this scene graph. scene.compile(); u = new SimpleUniverse(c); // This will move the ViewPlatform back a bit so the // objects in the scene can be viewed. u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); JOptionPane .showMessageDialog( this, "\nThis program measures the number of frames rendered per second.\nNote that the frame rate is limited by the refresh rate of the monitor.\nTo get the true frame rate you need to disable vertical retrace.\n\nOn Windows(tm) you do this through the Control Panel.\n\nOn Unix set the environment variable OGL_NO_VBLANK\n(i.e. type \"setenv OGL_NO_VBLANK\" at the command prompt)", "Frame Counter", JOptionPane.INFORMATION_MESSAGE); } public void destroy() { u.cleanup(); } // // The following allows FPSCounterDemo to be run as an application // as well as an applet // public static void main(String[] args) { FPSCounterDemo fp = new FPSCounterDemo(); fp.parseArgs(args); JMainFrame frame = new JMainFrame(fp, 256, 256); } /** * Parses the commandline for the various switches to set the FPSCounter * variables. All arguments are of the form <i>-name value </i>. All -name * arguments can be shortened to one character. All the value arguments take * a number. The arguments accepted are : * <ul> * <li>warmupTime : Specifies amount of time the FPSCounter should wait for * the HotSpot <sup><font size="-2">TM </font> </sup> VM to perform initial * optimizations. Specified in milliseconds <br> * <li>loopCount : Specifies the number of sampling intervals over which * the FPSCounter should calculate the aggregate and average frame rate. * Specified as a count. <br> * <li>maxLoops : Specifies that the FPSCounter should run for only these * many sampling intervals. Specified as number. If this argument is not * specified, the FPSCounter runs indefinitely. <br> * <li>help : Prints the accepted arguments. <br> * </ul> */ private void parseArgs(String args[]) { for (int i = 0; i < args.length; i++) { if (args[i].startsWith("-")) { if (args[i].startsWith("w", 1)) { i++; System.out.println("Warmup time : " + args[i]); int w = new Integer(args[i]).intValue(); fpsCounter.setWarmupTime(w); } else if (args[i].startsWith("l", 1)) { i++; System.out.println("Loop count : " + args[i]); int l = new Integer(args[i]).intValue(); fpsCounter.setLoopCount(l); } else if (args[i].startsWith("m", 1)) { i++; System.out.println("Max Loop Count : " + args[i]); int m = new Integer(args[i]).intValue(); fpsCounter.setMaxLoops(m); } else if (args[i].startsWith("h", 1)) { System.out .println("Usage : FPSCounterDemo [-name value]\n All arguments are of the form -name value. All -name arguments can be shortened to one character. All the value arguments take a number. The arguments accepted are :\n warmupTime : Specifies amount of time the FPSCounter should wait for the HotSpot(tm) VM to perform initial optimizations. Specified in milliseconds\n loopCount : Specifies the number of sampling intervals over which the FPSCounter should calculate the aggregate and average frame rate. Specified as a count\n maxLoops : Specifies that the FPSCounter should run for only these many sampling intervals. Specified as number. If this argument is not specified, the FPSCounter runs indefinitely.\n help : Prints this message."); } } } } } /** * This behavior calculates the frame rate and average frame rate of a Java3D * application. The behavior sets itself up to wakeup every time a new frame is * rendered. * * <p> * The HotSpot(tm) compiler performs some initial optimizations before running * at optimal speed. Frame rates measured during this warmup period will be * inaccurate and not indicative of the true performance of the the application. * Therefore, before beginning the frame rate computation, the frame counter * waits for a fixed time period to allow the HotSpot(tm) compiler to * stablilize. * * <p> * To avoid computing the frame rate too frequently (which would also hamper * rendering performance), the frame counter only computes the frame rate at * fixed time intervals. The default sampling duration is 10 seconds. After * waiting for the warmup period, the frame counter needs to calibrate itself. * It computes the number of frames rendered during the sampling period. After * doing this calibration, the frame counter reports the frame rate after these * many frames are rendered. It also reports the average frame rate after a * fixed number of sampling intervals (the default is 5). * * <p> * The frame counter can be set up to run for a fixed number of sampling * intervals or to run indefinitely. The defaultis to run indefinitely. */ class FPSCounter extends Behavior { // Wakeup condition - framecount = 0 -> wakeup on every frame WakeupOnElapsedFrames FPSwakeup = new WakeupOnElapsedFrames(0); // Do calibration for these many millisec private static final long testduration = 1000; // Report frame rate after every sampleduration milliseconds private static final long sampleduration = 10000; // Flag to indicate that it is time to (re)calibrate private boolean doCalibration = true; // Flag to indicate the counter has started private boolean startup = true; // Wait for HotSpot compiler to perform optimizations private boolean warmup = true; // Time to wait for HotSpot compiler to stabilize (in milliseconds) private long warmupTime = 20000; // Counter for number of frames rendered private int numframes = 0; // Report frame rate after maxframe number of frames have been rendered private int maxframes = 1; // Variables to keep track of elapsed time private long startuptime = 0; private long currtime = 0; private long lasttime = 0; private long deltatime; // Run indefinitely or for a fixed duration private boolean finiteLoop = false; // No. of sampling intervals to run for if not running indefinitely private long maxLoops; // No. of sampling intervals run for so far private long numLoops = 0; // Total number of frames rendered so far private int sumFrames = 0; // Total time since last reporting of average frame rate private long sumTimes = 0; // Counts no. of sampling intervals private int loop = 0; // Average frame rate is reported after loopCount number of // sampling intervals private int loopCount = 5; private double sumFps = 0.0; private String symbol[] = { "\\", "|", "|", "/", "-", "|", "-" }; int index = 0; private NumberFormat nf = null; public FPSCounter() { setEnable(true); nf = NumberFormat.getNumberInstance(); } // Called to init the behavior public void initialize() { // Set the trigger for the behavior to wakeup on every frame rendered wakeupOn(FPSwakeup); } // Called every time the behavior is activated public void processStimulus(java.util.Enumeration critera) { // Apply calibration algorithm to determine number of frames to // wait before computing frames per second. // sampleduration = 10000 -> to run test, pass for 10 seconds. if (doCalibration) { // start calibration if (startup) { // Record time at which the behavior was first invoked startuptime = System.currentTimeMillis(); startup = false; } else if (warmup) { // Wait for the system to stabilize. System.out.print("\rFPSCounter warming up..." + symbol[(index++) % symbol.length]); currtime = System.currentTimeMillis(); deltatime = currtime - startuptime; if (deltatime > warmupTime) { // Done waiting for warmup warmup = false; lasttime = System.currentTimeMillis(); System.out.println("\rFPSCounter warming up...Done"); } } else { numframes += 1; // Wait till at least maxframe no. of frames have been rendered if (numframes >= maxframes) { currtime = System.currentTimeMillis(); deltatime = currtime - lasttime; // Do the calibration for testduration no. of millisecs if (deltatime > testduration) { // Compute total no. of frames rendered so far in the // current sampling duration maxframes = (int) Math .ceil((double) numframes * ((double) sampleduration / (double) deltatime)); // Done with calibration doCalibration = false; // reset the value for the measurement numframes = 0; lasttime = System.currentTimeMillis(); } else { // Need to run the calibration routine for some more // time. Increase the no. of frames to be rendered maxframes *= 2; } } } } else { // do the measurement numframes += 1; if (numframes >= maxframes) { currtime = System.currentTimeMillis(); deltatime = currtime - lasttime; // time is in millisec, so multiply by 1000 to get frames/sec double fps = (double) numframes / ((double) deltatime / 1000.0); System.out.println("Frame Rate : \n\tNo. of frames : " + numframes + "\n\tTime : " + ((double) deltatime / 1000.0) + " sec." + "\n\tFrames/sec : " + nf.format(fps)); // Calculate average frame rate sumFrames += numframes; sumTimes += deltatime; sumFps += fps; loop++; if (loop >= loopCount) { double avgFps = (double) sumFrames * 1000.0 / (double) sumTimes; double ravgFps = sumFps / (double) loopCount; System.out.println("Aggregate frame rate " + nf.format(avgFps) + " frames/sec"); System.out.println("Average frame rate " + nf.format(ravgFps) + " frames/sec"); numLoops++; if (finiteLoop && numLoops >= maxLoops) { System.out.println("************** The End **************\n"); setEnable(false); } loop = 0; sumFps = 0; } numframes = 0; lasttime = System.currentTimeMillis(); ; } } // Set the trigger for the behavior wakeupOn(FPSwakeup); } /** * The frame counter waits for some time before computing the frame rate. * This allows the HotSpot compiler to perform initial optimizations. The * amount of time to wait for is set by this method. The default is 20000 * (20 sec) * * @param Amount * of time to wait for before computing frame rate (specified in * milliseconds) */ public void setWarmupTime(long wt) { warmupTime = wt; } /** * Sets the number of sampling intervals to wait for before computing the * average frame rate. The default is 5. * * @param No. * of sampling intervals over which to compute frame rate. A * value of 0 implies the average frame rate is computed over one * sampling interval */ public void setLoopCount(int lc) { loopCount = lc; } /** * This method sets the number of sampling intervals for which the frame * counter should run. * * @param No. * of sampling intervals to run for */ public void setMaxLoops(int ml) { maxLoops = ml; finiteLoop = true; } }