Use Java's timer to invoke our frame tick. Drop frames instead of queueing
up repeats when the previous tick takes too long. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1953 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: FrameManager.java,v 1.18 2002/10/26 20:31:15 mdb Exp $
|
||||
// $Id: FrameManager.java,v 1.19 2002/11/15 23:58:34 mdb Exp $
|
||||
|
||||
package com.threerings.media;
|
||||
|
||||
@@ -25,6 +25,10 @@ import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.RepaintManager;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.IntervalManager;
|
||||
import com.samskivert.util.ObserverList;
|
||||
@@ -150,13 +154,9 @@ public class FrameManager
|
||||
*/
|
||||
public void start ()
|
||||
{
|
||||
if (_ticker == null) {
|
||||
// create ticker for queueing up tick requests on AWT thread
|
||||
_ticker = new Ticker();
|
||||
// and start it up
|
||||
_ticker.start();
|
||||
// and kick off our first frame
|
||||
_ticker.tickIn(_millisPerFrame, System.currentTimeMillis());
|
||||
if (_timer == null) {
|
||||
_timer = new Timer(true);
|
||||
_timer.scheduleAtFixedRate(_callTick, new Date(), _millisPerFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,8 +165,9 @@ public class FrameManager
|
||||
*/
|
||||
public synchronized void stop ()
|
||||
{
|
||||
if (_ticker != null) {
|
||||
_ticker = null;
|
||||
if (_timer != null) {
|
||||
_timer.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,43 +177,44 @@ public class FrameManager
|
||||
*/
|
||||
public synchronized boolean isRunning ()
|
||||
{
|
||||
return (_ticker != null);
|
||||
return (_timer != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we are in the middle of a call to {@link #tick}.
|
||||
*/
|
||||
protected synchronized boolean isTicking ()
|
||||
{
|
||||
return _ticking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to perform the frame processing and rendering.
|
||||
*/
|
||||
protected void tick ()
|
||||
protected void tick (long tickStamp)
|
||||
{
|
||||
// if our frame is not showing (or is impossibly sized), don't try
|
||||
// rendering anything
|
||||
if (_frame.isShowing() &&
|
||||
_frame.getWidth() > 0 && _frame.getHeight() > 0) {
|
||||
long tickStamp = System.currentTimeMillis();
|
||||
// tick our participants
|
||||
tickParticipants(tickStamp);
|
||||
// repaint our participants
|
||||
paintParticipants(tickStamp);
|
||||
}
|
||||
try {
|
||||
synchronized (this) {
|
||||
_ticking = true;
|
||||
}
|
||||
|
||||
// now determine how many milliseconds we have left before we need
|
||||
// to start the next frame (if any)
|
||||
long end = System.currentTimeMillis();
|
||||
long duration = end - _frameStart;
|
||||
long remaining = _millisPerFrame - duration;
|
||||
// if our frame is not showing (or is impossibly sized), don't try
|
||||
// rendering anything
|
||||
if (_frame.isShowing() &&
|
||||
_frame.getWidth() > 0 && _frame.getHeight() > 0) {
|
||||
// tick our participants
|
||||
tickParticipants(tickStamp);
|
||||
// repaint our participants
|
||||
paintParticipants(tickStamp);
|
||||
}
|
||||
|
||||
// note that we've done a frame
|
||||
// PerformanceMonitor.tick(this, "frame-rate");
|
||||
|
||||
// if we have no time remaining, queue up another tick immediately
|
||||
if (remaining <= 0) {
|
||||
// make a note that we're starting our next frame now
|
||||
_frameStart = end;
|
||||
EventQueue.invokeLater(_callTick);
|
||||
|
||||
} else {
|
||||
// otherwise queue one up in the requisite number of millis
|
||||
_ticker.tickIn(remaining, end);
|
||||
} finally {
|
||||
synchronized (this) {
|
||||
_ticking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,57 +368,6 @@ public class FrameManager
|
||||
Log.info("Frames in last second: " + ticks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to queue up frame ticks on the AWT thread at some point in the
|
||||
* future.
|
||||
*/
|
||||
protected class Ticker extends Thread
|
||||
{
|
||||
/**
|
||||
* Tells the ticker to queue up a frame in the requisite number of
|
||||
* milliseconds.
|
||||
*/
|
||||
public synchronized void tickIn (long millis, long now)
|
||||
{
|
||||
_sleepfor = millis;
|
||||
_now = now;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
synchronized (this) {
|
||||
while (_sleepfor != -1) {
|
||||
try {
|
||||
if (_sleepfor == 0) {
|
||||
this.wait();
|
||||
}
|
||||
if (_sleepfor > 0) {
|
||||
Thread.sleep(_sleepfor);
|
||||
|
||||
// make a note of our frame start time
|
||||
_frameStart = System.currentTimeMillis();
|
||||
// long error =_frameStart - (_sleepfor + _now);
|
||||
// if (Math.abs(error) > 3) {
|
||||
// Log.warning("Funny business: " + error);
|
||||
// }
|
||||
|
||||
// queue up our ticker on the AWT thread
|
||||
EventQueue.invokeLater(_callTick);
|
||||
_sleepfor = 0;
|
||||
}
|
||||
|
||||
} catch (InterruptedException ie) {
|
||||
Log.warning("Girl interrupted!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected long _sleepfor = 0l;
|
||||
protected long _now = 0l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the off-screen buffer used to perform double buffered
|
||||
* rendering of the animated panel.
|
||||
@@ -585,15 +536,15 @@ public class FrameManager
|
||||
/** The image used to render off-screen. */
|
||||
protected VolatileImage _backimg;
|
||||
|
||||
/** The number of milliseconds per frame (12 by default, which gives
|
||||
* an fps of 80). */
|
||||
protected long _millisPerFrame = 12;
|
||||
/** The number of milliseconds per frame (14 by default, which gives
|
||||
* an fps of ~71). */
|
||||
protected long _millisPerFrame = 14;
|
||||
|
||||
/** The time at which we started the most recent "frame". */
|
||||
protected long _frameStart;
|
||||
/** The timer that dispatches our frame ticks. */
|
||||
protected Timer _timer;
|
||||
|
||||
/** Used to queue up a tick. */
|
||||
protected Ticker _ticker;
|
||||
/** Used to detect when we need to drop frames. */
|
||||
protected boolean _ticking;
|
||||
|
||||
/** The graphics object from our back buffer. */
|
||||
protected Graphics _bgfx;
|
||||
@@ -609,10 +560,16 @@ public class FrameManager
|
||||
* "layered" components. */
|
||||
protected boolean[] _clipped = new boolean[1];
|
||||
|
||||
/** Used to queue up a call to {@link #tick} on the AWT thread. */
|
||||
protected Runnable _callTick = new Runnable () {
|
||||
/** Used to effect periodic calls to {@link #tick}. */
|
||||
protected TimerTask _callTick = new TimerTask () {
|
||||
public void run () {
|
||||
tick();
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
tick(System.currentTimeMillis());
|
||||
} else if (!isTicking()) {
|
||||
EventQueue.invokeLater(this);
|
||||
} else {
|
||||
Log.info("Dropped frame.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user