framerater.go 2.5 KB

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