{-
   A simple frames-per-second counter
   Sven Panne 2000.   mailto:Sven.Panne@informatik.uni-muenchen.de
-}

module FPSCounter(
   FPSCounter, newFPSCounter, getFPS
) where

import Data.Array.IO
import Data.IORef
import Time

data FPSCounter =
   FPSCounter (IORef Int)               -- 0-based counter for averaging
              (IOArray Int ClockTime)   -- elapsed-time-array

newFPSCounter :: Int -> IO FPSCounter
newFPSCounter numUpdates = do
   counter <- newIORef 0
   -- The initial value is as wrong as any other, but it is
   -- automatically corrected after a wrap-around.
   ct <- getClockTime
   elapsedTimes <- newArray (1, numUpdates) ct
   return $ FPSCounter counter elapsedTimes

getFPS :: FPSCounter -> IO Float
getFPS (FPSCounter counter elapsedTimes) = do
   let (lo, hi)   = bounds elapsedTimes
       numUpdates = hi - lo + 1
   count <- readIORef counter
   oldElapsed <- readArray elapsedTimes (count + lo)
   newElapsed <- getClockTime
   writeIORef counter ((count + 1) `mod` numUpdates)
   writeArray elapsedTimes (count + lo) newElapsed
   return $ fromIntegral numUpdates /
            max (timeDiffInSecs (diffClockTimes newElapsed oldElapsed))
                1.0e-4   -- safety

-- ignoring year and month
timeDiffInSecs :: TimeDiff -> Float
timeDiffInSecs d =
   fromIntegral ((tdDay d * 24 + (tdHour d * 60 + tdMin d) * 60) + tdSec d) +
   fromIntegral (tdPicosec d) / 1.0E12
