| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- package util
- import (
- "time"
- )
- // FrameRater implements a frame rate controller
- type FrameRater struct {
- targetFPS uint // desired number of frames per second
- targetDuration time.Duration // calculated desired duration of frame
- frameStart time.Time // start time of last frame
- frameTimes time.Duration // accumulated frame times for potential FPS calculation
- frameCount uint // accumulated number of frames for FPS calculation
- lastUpdate time.Time // time of last FPS calculation update
- timer *time.Timer // timer for sleeping during frame
- }
- // NewFrameRater returns a frame rate controller object for the specified
- // number of target frames per second
- func NewFrameRater(targetFPS uint) *FrameRater {
- f := new(FrameRater)
- f.targetDuration = time.Second / time.Duration(targetFPS)
- f.frameTimes = 0
- f.frameCount = 0
- f.lastUpdate = time.Now()
- f.timer = time.NewTimer(0)
- <-f.timer.C
- return f
- }
- // Start should be called at the start of the frame
- func (f *FrameRater) Start() {
- f.frameStart = time.Now()
- }
- // Wait should be called at the end of the frame
- // If necessary it will sleep to achieve the desired frame rate
- func (f *FrameRater) Wait() {
- // Calculates the time duration of this frame
- elapsed := time.Now().Sub(f.frameStart)
- // Accumulates this frame time for potential FPS calculation
- f.frameCount++
- f.frameTimes += elapsed
- // If this frame duration is less than the target duration, sleeps
- // during the difference
- diff := f.targetDuration - elapsed
- if diff > 0 {
- f.timer.Reset(diff)
- <-f.timer.C
- }
- }
- // FPS calculates and returns the current measured FPS and the maximum
- // potential FPS after the specified time interval has elapsed.
- // It returns an indication if the results are valid
- func (f *FrameRater) FPS(t time.Duration) (float64, float64, bool) {
- // If the time from the last update has not passed, nothing to do
- elapsed := time.Now().Sub(f.lastUpdate)
- if elapsed < t {
- return 0, 0, false
- }
- // Calculates the measured average frame rate
- fps := float64(f.frameCount) / elapsed.Seconds()
- // Calculates the average duration of a frame and the potential FPS
- frameDur := f.frameTimes.Seconds() / float64(f.frameCount)
- pfps := 1.0 / frameDur
- // Resets the frame counter and times
- f.frameCount = 0
- f.frameTimes = 0
- f.lastUpdate = time.Now()
- return fps, pfps, true
- }
|