• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.jme3.system.lwjgl;
34 
35 import com.jme3.math.FastMath;
36 import com.jme3.system.Timer;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
39 import org.lwjgl.Sys;
40 
41 /**
42  * <code>Timer</code> handles the system's time related functionality. This
43  * allows the calculation of the framerate. To keep the framerate calculation
44  * accurate, a call to update each frame is required. <code>Timer</code> is a
45  * singleton object and must be created via the <code>getTimer</code> method.
46  *
47  * @author Mark Powell
48  * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $
49  */
50 public class LwjglSmoothingTimer extends Timer {
51     private static final Logger logger = Logger.getLogger(LwjglSmoothingTimer.class
52             .getName());
53 
54     private long lastFrameDiff;
55 
56     //frame rate parameters.
57     private long oldTime;
58 
59     private float lastTPF, lastFPS;
60 
61     public static int TIMER_SMOOTHNESS = 32;
62 
63     private long[] tpf;
64 
65     private int smoothIndex;
66 
67     private final static long LWJGL_TIMER_RES = Sys.getTimerResolution();
68     private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES );
69     private static float invTimerRezSmooth;
70 
71     public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES);
72 
73     private long startTime;
74 
75     private boolean allSmooth = false;
76 
77     /**
78      * Constructor builds a <code>Timer</code> object. All values will be
79      * initialized to it's default values.
80      */
LwjglSmoothingTimer()81     public LwjglSmoothingTimer() {
82         reset();
83 
84         //print timer resolution info
85         logger.log(Level.INFO, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES);
86     }
87 
reset()88     public void reset() {
89         lastFrameDiff = 0;
90         lastFPS = 0;
91         lastTPF = 0;
92 
93         // init to -1 to indicate this is a new timer.
94         oldTime = -1;
95         //reset time
96         startTime = Sys.getTime();
97 
98         tpf = new long[TIMER_SMOOTHNESS];
99         smoothIndex = TIMER_SMOOTHNESS - 1;
100         invTimerRezSmooth = ( 1f / (LWJGL_TIMER_RES * TIMER_SMOOTHNESS));
101 
102         // set tpf... -1 values will not be used for calculating the average in update()
103         for ( int i = tpf.length; --i >= 0; ) {
104             tpf[i] = -1;
105         }
106     }
107 
108     /**
109      * @see com.jme.util.Timer#getTime()
110      */
getTime()111     public long getTime() {
112         return Sys.getTime() - startTime;
113     }
114 
115     /**
116      * @see com.jme.util.Timer#getResolution()
117      */
getResolution()118     public long getResolution() {
119         return LWJGL_TIMER_RES;
120     }
121 
122     /**
123      * <code>getFrameRate</code> returns the current frame rate since the last
124      * call to <code>update</code>.
125      *
126      * @return the current frame rate.
127      */
getFrameRate()128     public float getFrameRate() {
129         return lastFPS;
130     }
131 
getTimePerFrame()132     public float getTimePerFrame() {
133         return lastTPF;
134     }
135 
136     /**
137      * <code>update</code> recalulates the frame rate based on the previous
138      * call to update. It is assumed that update is called each frame.
139      */
update()140     public void update() {
141         long newTime = Sys.getTime();
142         long oldTime = this.oldTime;
143         this.oldTime = newTime;
144         if ( oldTime == -1 ) {
145             // For the first frame use 60 fps. This value will not be counted in further averages.
146             // This is done so initialization code between creating the timer and the first
147             // frame is not counted as a single frame on it's own.
148             lastTPF = 1 / 60f;
149             lastFPS = 1f / lastTPF;
150             return;
151         }
152 
153         long frameDiff = newTime - oldTime;
154         long lastFrameDiff = this.lastFrameDiff;
155         if ( lastFrameDiff > 0 && frameDiff > lastFrameDiff *100 ) {
156             frameDiff = lastFrameDiff *100;
157         }
158         this.lastFrameDiff = frameDiff;
159         tpf[smoothIndex] = frameDiff;
160         smoothIndex--;
161         if ( smoothIndex < 0 ) {
162             smoothIndex = tpf.length - 1;
163         }
164 
165         lastTPF = 0.0f;
166         if (!allSmooth) {
167             int smoothCount = 0;
168             for ( int i = tpf.length; --i >= 0; ) {
169                 if ( tpf[i] != -1 ) {
170                     lastTPF += tpf[i];
171                     smoothCount++;
172                 }
173             }
174             if (smoothCount == tpf.length)
175                 allSmooth  = true;
176             lastTPF *= ( INV_LWJGL_TIMER_RES / smoothCount );
177         } else {
178             for ( int i = tpf.length; --i >= 0; ) {
179                 if ( tpf[i] != -1 ) {
180                     lastTPF += tpf[i];
181                 }
182             }
183             lastTPF *= invTimerRezSmooth;
184         }
185         if ( lastTPF < FastMath.FLT_EPSILON ) {
186             lastTPF = FastMath.FLT_EPSILON;
187         }
188 
189         lastFPS = 1f / lastTPF;
190     }
191 
192     /**
193      * <code>toString</code> returns the string representation of this timer
194      * in the format: <br>
195      * <br>
196      * jme.utility.Timer@1db699b <br>
197      * Time: {LONG} <br>
198      * FPS: {LONG} <br>
199      *
200      * @return the string representation of this object.
201      */
202     @Override
toString()203     public String toString() {
204         String string = super.toString();
205         string += "\nTime: " + oldTime;
206         string += "\nFPS: " + getFrameRate();
207         return string;
208     }
209 }