Commit 534c0ac4 authored by Raymond Gauthier's avatar Raymond Gauthier

Add a `withAnimFps` for manual animation sample rate specification

parent 524d7416
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
module IHaskell.Display.Diagrams module IHaskell.Display.Diagrams
( diagram, animation ( diagram, animation
, ManuallySized, withSizeSpec, withImgWidth, withImgHeight , ManuallySized, withSizeSpec, withImgWidth, withImgHeight
, ManuallySampled, withAnimFps
) where ) where
import qualified Data.ByteString.Char8 as Char import qualified Data.ByteString.Char8 as Char
......
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveFunctor, DeriveGeneric #-}
module IHaskell.Display.Diagrams.Animation (animation) where module IHaskell.Display.Diagrams.Animation
( animation
, ManuallySampled, withAnimFps
) where
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.ByteString.Char8 as CBS import qualified Data.ByteString.Char8 as CBS
import GHC.Generics (Generic)
import Data.Maybe (fromMaybe)
import Diagrams.Prelude import Diagrams.Prelude
import Diagrams.Backend.Cairo import Diagrams.Backend.Cairo
import Diagrams.Backend.Cairo.CmdLine (GifOpts(..)) import Diagrams.Backend.Cairo.CmdLine (GifOpts(..))
...@@ -14,21 +20,38 @@ import Diagrams.Backend.CmdLine (DiagramOpts(..), mainRender) ...@@ -14,21 +20,38 @@ import Diagrams.Backend.CmdLine (DiagramOpts(..), mainRender)
import IHaskell.Display import IHaskell.Display
import IHaskell.Display.Diagrams.ImgSize import IHaskell.Display.Diagrams.ImgSize
instance IHaskellDisplay (ManuallySized (QAnimation Cairo V2 Double Any)) where
data ManuallySampled a = ManuallySampled
{ contentToSample :: a
, signalManualSampleRate :: Maybe Rational
} deriving (Show, Functor, Generic)
class ManuallySamplable a where
withSamplingSpec :: Maybe Rational -> a -> ManuallySampled a
defaultFps = 30
withAnimFps :: ManuallySamplable a => Rational -> a -> ManuallySampled a
withAnimFps fps = withSamplingSpec (Just fps)
instance IHaskellDisplay (ManuallySized (ManuallySampled (QAnimation Cairo V2 Double Any))) where
display renderable = do display renderable = do
gif <- animationData renderable gif <- animationData renderable
return $ Display [html $ "<img src=\"data:image/gif;base64," return $ Display [html $ "<img src=\"data:image/gif;base64,"
++ gif ++ "\" />"] ++ gif ++ "\" />"]
animationData :: ManuallySized (Animation Cairo V2 Double) -> IO String
animationData (ManuallySized renderable imgWidth imgHeight) = do animationData :: ManuallySized (ManuallySampled (Animation Cairo V2 Double)) -> IO String
animationData (ManuallySized (ManuallySampled renderable fps) imgWidth imgHeight) = do
switchToTmpDir switchToTmpDir
-- Generate the frames -- Generate the frames
let fps = 30 let actualFps = fromMaybe defaultFps fps
animAdjusted = animEnvelope' fps renderable animAdjusted = animEnvelope' actualFps renderable
frames = simulate fps animAdjusted frames = simulate actualFps animAdjusted
timediff = 100 `div` ceiling fps :: Int timediff = 100 `div` ceiling actualFps :: Int
frameSet = map (\x -> (x # bg white, timediff)) frames frameSet = map (\x -> (x # bg white, timediff)) frames
-- Write the image. -- Write the image.
...@@ -45,29 +68,70 @@ animationData (ManuallySized renderable imgWidth imgHeight) = do ...@@ -45,29 +68,70 @@ animationData (ManuallySized renderable imgWidth imgHeight) = do
imgData <- CBS.readFile filename imgData <- CBS.readFile filename
return . T.unpack . base64 $ imgData return . T.unpack . base64 $ imgData
-- Rendering hint. -- Rendering hint.
animation :: Animation Cairo V2 Double -> Animation Cairo V2 Double animation :: Animation Cairo V2 Double -> Animation Cairo V2 Double
animation = id animation = id
getImgSize renderable sizeSpec fps = out
where
actualFps = fromMaybe defaultFps fps
shape = activeStart $ animEnvelope' actualFps renderable
aspect = width shape / height shape
out = case getSpec sizeSpec of
V2 (Just w) (Just h) -> V2 w h
V2 (Just w) Nothing -> V2 w (w/aspect)
V2 Nothing (Just h) -> V2 (aspect*h) h
V2 Nothing Nothing -> (defaultDiagonal / sqrt (1 + aspect^2))
*^ V2 aspect 1
-- w^2 + h^2 = defaultDiagonal^2 / (1+aspect^2)
-- * (aspect^2 + 1)
-- = defaultDiagonal^2
-- w/h = aspect/1 = aspect
defaultDiagonal = 500
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
=> ManuallySamplable (QAnimation b v s m) where
withSamplingSpec fps renderable = ManuallySampled renderable fps
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
=> ManuallySamplable (ManuallySized (QAnimation b v s m)) where
withSamplingSpec fps sizedRenderable = ManuallySampled sizedRenderable fps
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any) instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
=> ManuallySizeable (QAnimation b v s m) where => ManuallySizeable (QAnimation b v s m) where
withSizeSpec spec renderable = ManuallySized renderable imgWidth imgHeight withSizeSpec spec renderable = ManuallySized renderable imgWidth imgHeight
where where
fps = 30 fps = Nothing
shape = activeStart $ animEnvelope' fps renderable V2 imgWidth imgHeight = getImgSize renderable spec fps
aspect = width shape / height shape
V2 imgWidth imgHeight = case getSpec spec of instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
V2 (Just w) (Just h) -> V2 w h => ManuallySizeable (ManuallySampled (QAnimation b v s m)) where
V2 (Just w) Nothing -> V2 w (w/aspect) withSizeSpec spec (ManuallySampled renderable fps) = out
V2 Nothing (Just h) -> V2 (aspect*h) h where
V2 Nothing Nothing -> (defaultDiagonal / sqrt (1 + aspect^2)) out = ManuallySized (ManuallySampled renderable fps) w h
*^ V2 aspect 1 V2 w h = getImgSize renderable spec fps
-- w^2 + h^2 = defaultDiagonal^2 / (1+aspect^2)
-- * (aspect^2 + 1)
-- = defaultDiagonal^2
-- w/h = aspect/1 = aspect
defaultDiagonal = 500
instance IHaskellDisplay (QAnimation Cairo V2 Double Any) where instance IHaskellDisplay (QAnimation Cairo V2 Double Any) where
display = display . withSizeSpec (mkSizeSpec2D Nothing Nothing) . withSamplingSpec fps
where
fps = Nothing
instance IHaskellDisplay (ManuallySized (QAnimation Cairo V2 Double Any)) where
display (ManuallySized renderable w h) = out
where
fps = Nothing
sizeSpec = mkSizeSpec2D (Just w) (Just h)
out = display . withSizeSpec sizeSpec $ withSamplingSpec fps renderable
instance IHaskellDisplay (ManuallySampled (QAnimation Cairo V2 Double Any)) where
display = display . withSizeSpec (mkSizeSpec2D Nothing Nothing) display = display . withSizeSpec (mkSizeSpec2D Nothing Nothing)
instance IHaskellDisplay (ManuallySampled (ManuallySized (QAnimation Cairo V2 Double Any))) where
display (ManuallySampled (ManuallySized renderable w h) fps) = out
where
sizeSpec = mkSizeSpec2D (Just w) (Just h)
out = display . withSizeSpec sizeSpec $ withSamplingSpec fps renderable
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment