framerater.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package application
  2. import (
  3. "time"
  4. )
  5. // FrameRater implements a frame rate controller
  6. type FrameRater struct {
  7. targetFPS uint // desired number of frames per second
  8. targetDuration time.Duration // calculated desired duration of frame
  9. frameStart time.Time // start time of last frame
  10. frameTimes time.Duration // accumulated frame times for potential FPS calculation
  11. frameCount uint // accumulated number of frames for FPS calculation
  12. lastUpdate time.Time // time of last FPS calculation update
  13. timer *time.Timer // timer for sleeping during frame
  14. }
  15. // NewFrameRater returns a frame rate controller object for the specified
  16. // number of target frames per second
  17. func NewFrameRater(targetFPS uint) *FrameRater {
  18. f := new(FrameRater)
  19. f.targetDuration = time.Second / time.Duration(targetFPS)
  20. f.frameTimes = 0
  21. f.frameCount = 0
  22. f.lastUpdate = time.Now()
  23. f.timer = time.NewTimer(0)
  24. <-f.timer.C
  25. return f
  26. }
  27. // Start should be called at the start of the frame
  28. func (f *FrameRater) Start() {
  29. f.frameStart = time.Now()
  30. }
  31. // Wait should be called at the end of the frame
  32. // If necessary it will sleep to achieve the desired frame rate
  33. func (f *FrameRater) Wait() {
  34. // Calculates the time duration of this frame
  35. elapsed := time.Now().Sub(f.frameStart)
  36. // Accumulates this frame time for potential FPS calculation
  37. f.frameCount++
  38. f.frameTimes += elapsed
  39. // If this frame duration is less than the target duration, sleeps
  40. // during the difference
  41. diff := f.targetDuration - elapsed
  42. if diff > 0 {
  43. f.timer.Reset(diff)
  44. <-f.timer.C
  45. }
  46. }
  47. // FPS calculates and returns the current measured FPS and the maximum
  48. // potential FPS after the specified time interval has elapsed.
  49. // It returns an indication if the results are valid
  50. func (f *FrameRater) FPS(t time.Duration) (float64, float64, bool) {
  51. // If the time from the last update has not passed, nothing to do
  52. elapsed := time.Now().Sub(f.lastUpdate)
  53. if elapsed < t {
  54. return 0, 0, false
  55. }
  56. // Calculates the measured average frame rate
  57. fps := float64(f.frameCount) / elapsed.Seconds()
  58. // Calculates the average duration of a frame and the potential FPS
  59. frameDur := f.frameTimes.Seconds() / float64(f.frameCount)
  60. pfps := 1.0 / frameDur
  61. // Resets the frame counter and times
  62. f.frameCount = 0
  63. f.frameTimes = 0
  64. f.lastUpdate = time.Now()
  65. return fps, pfps, true
  66. }