001: /*
002: * Copyright (c) 2001 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: * @Author: Silvere Martin-Michiellot
032: *
033: */
034:
035: package com.db.utils.timers;
036:
037: // This code is repackaged after the code from Joerg Plewe
038: // Site http://www.hardcode.de/
039: // Email plewe@hardcode.de
040:
041: public class FrameClock {
042:
043: static int mono = Integer.MIN_VALUE;
044:
045: private int lastSnap = -1;
046:
047: private int adjust = 0;
048:
049: private final int maxFrameTimerCount = 100;
050: private int FrameTimerCount = maxFrameTimerCount;
051: private int[] FrameTimer;
052: private int lastFrameMillis;
053: private int FrameTimerIndex = 0;
054: private int averageFrameTime = 40;
055: private int countNoTimerChange = 0;
056:
057: private float averageFPS = 25.0f;
058:
059: private int m_shiftFromAverage = 0;
060:
061: public FrameClock() {
062:
063: calibrate();
064:
065: }
066:
067: public void adjust(int _Adjustment) {
068:
069: // Shift the adjustment
070: adjust -= _Adjustment;
071:
072: // reset the timer
073: reset();
074:
075: }
076:
077: public void maintainFrameTiming() {
078:
079: int currentMillis = (int) System.currentTimeMillis() - adjust;
080: int FrameTimeDiff = currentMillis - lastFrameMillis;
081:
082: FrameTimer[FrameTimerIndex] = FrameTimeDiff;
083: FrameTimerIndex++;
084: FrameTimerIndex %= FrameTimerCount;
085:
086: if (FrameTimeDiff > 0) {
087: m_shiftFromAverage += (((countNoTimerChange + 1) * averageFrameTime) - FrameTimeDiff);
088:
089: // Reduce shift so it does not walk away
090: m_shiftFromAverage = (m_shiftFromAverage * 9) / 10;
091:
092: lastFrameMillis = currentMillis;
093: countNoTimerChange = 0;
094: } else
095: countNoTimerChange++;
096:
097: // Remember an average FPS value at reasonables distances
098: if (FrameTimerIndex == 0) {
099: updateAverages();
100: // System.out.println( getFPS() );
101: }
102:
103: // Check quality of timer
104: if (mono > getTimeNextFrame()) {
105: System.out.print("Timer not monotone! Backstep is ");
106: System.out.println(mono - getTimeNextFrame());
107: }
108: mono = getTimeNextFrame();
109:
110: }
111:
112: public int getTimeNextFrame() {
113:
114: return lastFrameMillis + m_shiftFromAverage
115: + ((countNoTimerChange + 1) * averageFrameTime);
116:
117: }
118:
119: public float getFPS() {
120:
121: return averageFPS;
122:
123: }
124:
125: public float getAverageFrameTime() {
126:
127: return (float) averageFrameTime;
128:
129: }
130:
131: /** Get the time since last frame. Same as getAverageFrameTime()
132: * @return normalized time since last frame in milliseconds
133: */
134: public float getFrameTimeDelta() {
135:
136: return (float) averageFrameTime;
137:
138: }
139:
140: /** calibrate the timer by measuring the timer accuracy and setting the internal
141: * averaging parameters
142: */
143: private void calibrate() {
144:
145: FrameTimerCount = (int) new TimerAccuracy().measure(200) / 2;
146:
147: if (FrameTimerCount < 5)
148: FrameTimerCount = 5;
149:
150: if (FrameTimerCount >= maxFrameTimerCount)
151: FrameTimerCount = maxFrameTimerCount - 1;
152:
153: FrameTimer = new int[FrameTimerCount];
154:
155: for (int i = 0; i < FrameTimerCount; ++i) {
156: FrameTimer[i] = averageFrameTime;
157: }
158:
159: reset();
160: updateAverages();
161:
162: }
163:
164: /** Reset timer
165: */
166: public void reset() {
167:
168: lastFrameMillis = (int) System.currentTimeMillis() - adjust;
169:
170: }
171:
172: private void updateAverages() {
173:
174: averageFrameTime = 0;
175: for (int i = 0; i < FrameTimerCount; ++i) {
176: averageFrameTime += FrameTimer[i];
177: }
178: averageFrameTime /= FrameTimerCount;
179:
180: averageFPS = 1000.0f / (float) averageFrameTime;
181:
182: }
183:
184: }
|