Refuse to allow a frame participant to be added more than once; enhanced
FPS display, made it possible for frame participants to add to the performance status string. Also modified perf status to be double buffered. It's not repainting exactly properly at the moment; soon to be remedied. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2041 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: FrameManager.java,v 1.29 2002/12/04 23:21:25 mdb Exp $
|
||||
// $Id: FrameManager.java,v 1.30 2002/12/08 02:49:12 mdb Exp $
|
||||
|
||||
package com.threerings.media;
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.applet.Applet;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Frame;
|
||||
@@ -34,6 +35,7 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.RepaintManager;
|
||||
|
||||
import com.samskivert.swing.Label;
|
||||
import com.samskivert.util.DebugChords;
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.IntervalManager;
|
||||
@@ -97,6 +99,15 @@ import com.threerings.media.timer.SystemMediaTimer;
|
||||
*/
|
||||
public class FrameManager
|
||||
{
|
||||
/** {@link FrameParticipant}s can implement this interface and be
|
||||
* added to the performance display. */
|
||||
public static interface PerformanceProvider
|
||||
{
|
||||
/** Returns a string that will be appended to the debug
|
||||
* performance display drawn on top of the frame. */
|
||||
public void getPerformanceStatus (StringBuffer buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a frame manager that will use a {@link SystemMediaTimer} to
|
||||
* obtain timing information, which is available on every platform,
|
||||
@@ -157,7 +168,12 @@ public class FrameManager
|
||||
*/
|
||||
public void registerFrameParticipant (FrameParticipant participant)
|
||||
{
|
||||
_participants.add(participant);
|
||||
if (_participants.contains(participant)) {
|
||||
Log.warning("Ingoring already registered participant " +
|
||||
participant + ".");
|
||||
} else {
|
||||
_participants.add(participant);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,26 +194,6 @@ public class FrameManager
|
||||
return _timer.getElapsedMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frequency with which the frame manager is attempting to
|
||||
* call {@link #tick}.
|
||||
*/
|
||||
public float getAttemptedFramesPerSecond ()
|
||||
{
|
||||
return _fps[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frequency with which the frame manager is able to call
|
||||
* {@link #tick} given that frames must be dropped if the previous
|
||||
* call to {@link #tick} has not finished when the time comes for the
|
||||
* next call.
|
||||
*/
|
||||
public float getAchievedFramesPerSecond ()
|
||||
{
|
||||
return _fps[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts up the per-frame tick
|
||||
*/
|
||||
@@ -266,14 +262,17 @@ public class FrameManager
|
||||
Log.logStackTrace(t);
|
||||
}
|
||||
|
||||
if (_displayFPS) {
|
||||
// handle frames per second status updates
|
||||
tickFramesPerSecondView();
|
||||
if (_displayPerf) {
|
||||
startPerformanceStatusTick();
|
||||
}
|
||||
|
||||
// tick all of our frame participants
|
||||
_participantTickOp.setTickStamp(tickStamp);
|
||||
_participants.apply(_participantTickOp);
|
||||
|
||||
if (_displayPerf) {
|
||||
finishPerformanceStatusTick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,12 +323,21 @@ public class FrameManager
|
||||
|
||||
// paint our frame participants (which want to be handled
|
||||
// specially)
|
||||
_bgfx.setFont(_saveFont);
|
||||
_participantPaintOp.setGraphics(_bgfx);
|
||||
_participants.apply(_participantPaintOp);
|
||||
|
||||
// repaint any widgets that have declared they need to be
|
||||
// repainted since the last tick
|
||||
_bgfx.setFont(_saveFont);
|
||||
_remgr.paintComponents(_bgfx, this);
|
||||
_saveFont = _bgfx.getFont();
|
||||
|
||||
if (_displayPerf && _perfLabel != null) {
|
||||
// render the current performance status
|
||||
_bgfx.setClip(null);
|
||||
_perfLabel.render((Graphics2D)_bgfx, FPS_X, FPS_Y);
|
||||
}
|
||||
|
||||
// we cache our frame's graphics object so that we can avoid
|
||||
// instantiating a new one on every tick
|
||||
@@ -338,11 +346,6 @@ public class FrameManager
|
||||
}
|
||||
_fgfx.drawImage(_backimg, 0, 0, null);
|
||||
|
||||
if (_displayFPS) {
|
||||
// render the current frames per second status
|
||||
renderFramesPerSecondView();
|
||||
}
|
||||
|
||||
// _bufstrat.show();
|
||||
|
||||
// if we loop through a second time, we'll need to rerender
|
||||
@@ -353,57 +356,53 @@ public class FrameManager
|
||||
}
|
||||
|
||||
/**
|
||||
* If frame rate display is enabled, this method is called every frame
|
||||
* to update the frame rate display and dirty things as necessary.
|
||||
* If frame rate display is enabled, builds beginning of performance
|
||||
* status display.
|
||||
*/
|
||||
protected void tickFramesPerSecondView ()
|
||||
protected void startPerformanceStatusTick ()
|
||||
{
|
||||
// we can't do anything unless we've got our main image
|
||||
if (_bgfx == null) {
|
||||
return;
|
||||
}
|
||||
if (_perfTicks++ % 100 == 0) {
|
||||
_perfStatus = new StringBuffer();
|
||||
_perfStatus.append("[FPS: ");
|
||||
_perfStatus.append(Math.round(_fps[1])).append("/");
|
||||
_perfStatus.append(Math.round(_fps[0]));
|
||||
|
||||
// update our attained and achieved framerate information
|
||||
int ofpsatt = _fpsatt, ofpsach = _fpsach;
|
||||
_fpsatt = Math.round(getAttemptedFramesPerSecond());
|
||||
_fpsach = Math.round(getAchievedFramesPerSecond());
|
||||
|
||||
if (ofpsatt != _fpsatt || ofpsach != _fpsach) {
|
||||
// build the string we'll render when the time comes
|
||||
_fpsinfo = "[FPS: " + _fpsach + " / " + _fpsatt + "]";
|
||||
|
||||
if (_fpsmetrics == null) {
|
||||
// grab the font metrics used to determine string dimensions
|
||||
_fpsmetrics = _bgfx.getFontMetrics(_fpsfont);
|
||||
if (_perfLabel == null) {
|
||||
_perfLabel = new Label(
|
||||
"", Label.OUTLINE, Color.white, Color.black,
|
||||
new Font("Arial", Font.PLAIN, 10));
|
||||
}
|
||||
|
||||
// dirty the rectangle in which we'll be doing our business
|
||||
int swid = _fpsmetrics.stringWidth(_fpsinfo);
|
||||
int fhei = _fpsmetrics.getHeight();
|
||||
JComponent comp = (JComponent)((JFrame)_frame).getRootPane();
|
||||
_remgr.addDirtyRegion(comp, FPS_X, FPS_Y, swid, fhei);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If frame rate display is enabled, this method is called every frame
|
||||
* to render the current frames per second information to the frame
|
||||
* buffer.
|
||||
* If frame rate display is enabled, prepares to render new
|
||||
* performance status if it has changed.
|
||||
*/
|
||||
protected void renderFramesPerSecondView ()
|
||||
protected void finishPerformanceStatusTick ()
|
||||
{
|
||||
// bail if we've not got the frame buffer or our font metrics
|
||||
if (_fgfx == null || _fpsmetrics == null) {
|
||||
if (_perfStatus == null) {
|
||||
return;
|
||||
}
|
||||
_perfStatus.append("]");
|
||||
_perfLabel.setText(_perfStatus.toString());
|
||||
_perfStatus = null;
|
||||
|
||||
if (_bgfx == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// render the business
|
||||
_fgfx.setColor(Color.white);
|
||||
Font ofont = _fgfx.getFont();
|
||||
_fgfx.setFont(_fpsfont);
|
||||
int fhei = _fpsmetrics.getHeight();
|
||||
_fgfx.drawString(_fpsinfo, FPS_X, FPS_Y + fhei);
|
||||
_fgfx.setFont(ofont);
|
||||
// dirty our previous bounds
|
||||
JComponent comp = (JComponent)((JFrame)_frame).getRootPane();
|
||||
Dimension lsize = _perfLabel.getSize();
|
||||
_remgr.addDirtyRegion(comp, FPS_X, FPS_Y, lsize.width, lsize.height);
|
||||
|
||||
// re-layout our status label
|
||||
_perfLabel.layout((Graphics2D)_bgfx);
|
||||
|
||||
// dirty our new bounds
|
||||
lsize = _perfLabel.getSize();
|
||||
_remgr.addDirtyRegion(comp, FPS_X, FPS_Y, lsize.width, lsize.height);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,6 +484,7 @@ public class FrameManager
|
||||
// fill the back buffer with white
|
||||
_bgfx = _backimg.getGraphics();
|
||||
_bgfx.fillRect(0, 0, width, height);
|
||||
_saveFont = _bgfx.getFont();
|
||||
|
||||
// clear out our frame graphics in case that became invalid for
|
||||
// the same reasons our back buffer became invalid
|
||||
@@ -538,6 +538,15 @@ public class FrameManager
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// if this frame participant is a performance provider,
|
||||
// let the add their business to the performance status
|
||||
if ((_perfStatus != null) &&
|
||||
(observer instanceof PerformanceProvider)) {
|
||||
_perfStatus.append(", ");
|
||||
((PerformanceProvider)
|
||||
observer).getPerformanceStatus(_perfStatus);
|
||||
}
|
||||
|
||||
((FrameParticipant)observer).tick(_tickStamp);
|
||||
|
||||
if (HANG_DEBUG) {
|
||||
@@ -651,63 +660,6 @@ public class FrameManager
|
||||
protected Rectangle _bounds = new Rectangle();
|
||||
}
|
||||
|
||||
/** The frame into which we do our rendering. */
|
||||
protected Frame _frame;
|
||||
|
||||
/** Used to obtain timing measurements. */
|
||||
protected MediaTimer _timer;
|
||||
|
||||
/** Our custom repaint manager. */
|
||||
protected FrameRepaintManager _remgr;
|
||||
|
||||
// /** The buffer strategy used to do our rendering. */
|
||||
// protected BufferStrategy _bufstrat;
|
||||
|
||||
/** The image used to render off-screen. */
|
||||
protected VolatileImage _backimg;
|
||||
|
||||
/** The number of milliseconds per frame (14 by default, which gives
|
||||
* an fps of ~71). */
|
||||
protected long _millisPerFrame = 14;
|
||||
|
||||
/** Used to track big delays in calls to our tick method. */
|
||||
protected long _lastTickStamp;
|
||||
|
||||
/** The timer that dispatches our frame ticks. */
|
||||
protected Timer _ticker;
|
||||
|
||||
/** Used to track and report frames per second. */
|
||||
protected float[] _fps = new float[2];
|
||||
|
||||
/** The graphics object from our back buffer. */
|
||||
protected Graphics _bgfx;
|
||||
|
||||
/** The graphics object from our frame. */
|
||||
protected Graphics _fgfx;
|
||||
|
||||
/** Used to avoid creating rectangles when rendering layered
|
||||
* components. */
|
||||
protected Rectangle _lbounds = new Rectangle();
|
||||
|
||||
/** Used to lazily set the clip when painting popups and other
|
||||
* "layered" components. */
|
||||
protected boolean[] _clipped = new boolean[1];
|
||||
|
||||
/** The font metrics used when rendering frames per second status. */
|
||||
protected FontMetrics _fpsmetrics;
|
||||
|
||||
/** The frames per second status info string. */
|
||||
protected String _fpsinfo = "";
|
||||
|
||||
/** The last frames per second information displayed. */
|
||||
protected int _fpsatt = -1, _fpsach = -1;
|
||||
|
||||
/** The font used to render the frames per second status. */
|
||||
protected Font _fpsfont = new Font("Arial", Font.PLAIN, 10);
|
||||
|
||||
/** Whether the frame rate display is enabled. */
|
||||
protected boolean _displayFPS;
|
||||
|
||||
/** Used to effect periodic calls to {@link #tick}. */
|
||||
protected TimerTask _callTick = new TimerTask () {
|
||||
public void run ()
|
||||
@@ -765,6 +717,64 @@ public class FrameManager
|
||||
protected long _lastTick;
|
||||
};
|
||||
|
||||
/** The frame into which we do our rendering. */
|
||||
protected Frame _frame;
|
||||
|
||||
/** Used to obtain timing measurements. */
|
||||
protected MediaTimer _timer;
|
||||
|
||||
/** Our custom repaint manager. */
|
||||
protected FrameRepaintManager _remgr;
|
||||
|
||||
// /** The buffer strategy used to do our rendering. */
|
||||
// protected BufferStrategy _bufstrat;
|
||||
|
||||
/** The image used to render off-screen. */
|
||||
protected VolatileImage _backimg;
|
||||
|
||||
/** The number of milliseconds per frame (14 by default, which gives
|
||||
* an fps of ~71). */
|
||||
protected long _millisPerFrame = 14;
|
||||
|
||||
/** Used to track big delays in calls to our tick method. */
|
||||
protected long _lastTickStamp;
|
||||
|
||||
/** The timer that dispatches our frame ticks. */
|
||||
protected Timer _ticker;
|
||||
|
||||
/** Used to track and report frames per second. */
|
||||
protected float[] _fps = new float[2];
|
||||
|
||||
/** The graphics object from our back buffer. */
|
||||
protected Graphics _bgfx;
|
||||
|
||||
/** The graphics object from our frame. */
|
||||
protected Graphics _fgfx;
|
||||
|
||||
/** We try to preserve the font in between renders in case other
|
||||
* things mess with it. */
|
||||
protected Font _saveFont;
|
||||
|
||||
/** Used to avoid creating rectangles when rendering layered
|
||||
* components. */
|
||||
protected Rectangle _lbounds = new Rectangle();
|
||||
|
||||
/** Used to lazily set the clip when painting popups and other
|
||||
* "layered" components. */
|
||||
protected boolean[] _clipped = new boolean[1];
|
||||
|
||||
/** The label used to render peformance status. */
|
||||
protected Label _perfLabel;
|
||||
|
||||
/** Used to build the performance status text. */
|
||||
protected StringBuffer _perfStatus;
|
||||
|
||||
/** Used when reporting performance status. */
|
||||
protected int _perfTicks;
|
||||
|
||||
/** Whether the performance status display is enabled. */
|
||||
protected boolean _displayPerf;
|
||||
|
||||
/** The entites that are ticked each frame. */
|
||||
protected ObserverList _participants =
|
||||
new ObserverList(ObserverList.FAST_UNSAFE_NOTIFY);
|
||||
@@ -796,9 +806,9 @@ public class FrameManager
|
||||
/** A debug hook that allows toggling the frame rate display. */
|
||||
protected DebugChords.Hook FPS_DISPLAY_HOOK = new DebugChords.Hook() {
|
||||
public void invoke () {
|
||||
_displayFPS = !_displayFPS;
|
||||
Log.info("Toggling frame rate display " +
|
||||
"[enabled=" + _displayFPS + "].");
|
||||
_displayPerf = !_displayPerf;
|
||||
Log.info((_displayPerf ? "Enabling" : "Disabling") +
|
||||
" performance status display.");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user