Home | History | Annotate | Download | only in lwjgl
      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      */
     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 
     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      */
    111     public long getTime() {
    112         return Sys.getTime() - startTime;
    113     }
    114 
    115     /**
    116      * @see com.jme.util.Timer#getResolution()
    117      */
    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      */
    128     public float getFrameRate() {
    129         return lastFPS;
    130     }
    131 
    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      */
    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
    203     public String toString() {
    204         String string = super.toString();
    205         string += "\nTime: " + oldTime;
    206         string += "\nFPS: " + getFrameRate();
    207         return string;
    208     }
    209 }