001         package com.croftsoft.core.animation.clock;
002    
003         import com.croftsoft.core.animation.Clock;
004    
005         /*********************************************************************
006         * A Clock with higher resolution than the system clock.
007         *
008         * <p>
009         * The system clock on some platforms has a granularity as poor as
010         * 50 or 60 milliseconds.  For some applications, such as high
011         * frequency animation, this is insufficient.  Film quality animation
012         * of 24 frames per second, for example, has a period of 41.667
013         * milliseconds.  This class provides high resolution timing with a
014         * granularity of one nanosecond.
015         * </p>
016         *
017         * <p>
018         * The current implementation samples the system clock each time the
019         * method currentTimeNanos() is called.  The period between method
020         * calls is then estimated using round robin windowed averaging.
021         * Assuming the method is called fairly periodically within a loop,
022         * the returned value will be the previous value plus the updated
023         * period estimate whenever the system clock has not been increased.
024         * </p>
025         *
026         * @see
027         *   SystemClock
028         *
029         * @version
030         *   2002-12-01
031         * @since
032         *   2002-03-11
033         * @author
034         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
035         *********************************************************************/
036    
037         public final class  HiResClock
038           implements Clock
039         //////////////////////////////////////////////////////////////////////
040         //////////////////////////////////////////////////////////////////////
041         {
042    
043         private final int  SAMPLES_LENGTH = 1000;
044    
045         //
046    
047         private long [ ]  samples = new long [ SAMPLES_LENGTH ];
048    
049         private long      lastClockTimeNanos;
050    
051         private int       index;
052    
053         private long      estimatedTimeNanos;
054    
055         private boolean   arrayFilled;
056    
057         private long      estimatedPeriodNanos;
058    
059         //////////////////////////////////////////////////////////////////////
060         //////////////////////////////////////////////////////////////////////
061    
062         public long  currentTimeNanos ( )
063         //////////////////////////////////////////////////////////////////////
064         {
065           long  clockTimeNanos = 1000000L * System.currentTimeMillis ( );
066    
067           // round robin windowed averaging
068    
069           if ( arrayFilled )
070           {
071             estimatedPeriodNanos
072               = ( clockTimeNanos - samples [ index ] ) / SAMPLES_LENGTH;
073           }
074           else
075           {
076             if ( index == 0 )
077             {
078               estimatedPeriodNanos = 0;
079             }
080             else
081             { 
082               estimatedPeriodNanos
083                 = ( clockTimeNanos - samples [ 0 ] ) / index;
084             }
085    
086             if ( index == SAMPLES_LENGTH - 1 )
087             {
088               arrayFilled = true;
089             }
090           }
091    
092           if ( ( estimatedPeriodNanos > 100000000L )
093             || ( clockTimeNanos > lastClockTimeNanos + 100000000L ) )
094           {
095             estimatedPeriodNanos = 0;
096    
097             index = 0;
098    
099             arrayFilled = false;
100           }
101    
102           samples [ index ] = clockTimeNanos;
103    
104           index = ( index + 1 ) % SAMPLES_LENGTH;
105    
106           if ( clockTimeNanos > lastClockTimeNanos )
107           {
108             if ( clockTimeNanos > estimatedTimeNanos )
109             {
110               estimatedTimeNanos = clockTimeNanos;
111             }
112           }
113           else
114           {
115             estimatedTimeNanos += estimatedPeriodNanos;
116           }
117    
118           lastClockTimeNanos = clockTimeNanos;
119    
120    /*
121    System.out.print ( clockTimeNanos );
122    
123    System.out.print ( " " );
124    
125    System.out.print ( estimatedPeriodNanos );
126    
127    System.out.print ( " " );
128    
129    System.out.println ( estimatedTimeNanos );
130    */
131    
132           return estimatedTimeNanos;
133         }
134    
135         //////////////////////////////////////////////////////////////////////
136         //////////////////////////////////////////////////////////////////////
137         }