|
How to create a frames per second counter |
|
|
This Java 3D 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.
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;
}
}
|
Related Tips
|
Page 1 of 0 ( 0 comments )
You can share your information about this topic using the form below!
Please do not post your questions with this form! Thanks.