frame :: Render -> Size -> Zoom -> Float -> G.Picture
frame render size zoom time = G.scale zoom' zoom' pic
  where
    -- Scale the time to be the phi value of the animation. The action seems to
    -- slow down at increasing phi values, so we increase phi faster as time
    -- moves on.
    x           = 1 + (time ** 1.5) * 0.005

    -- lift to a singleton array, else we would generate new code with the
    -- constant embedded at every frame
    phi         = A.fromList Z [pi / x]

    -- Compute the image
    arrPixels   = render phi

    -- Wrap the array data in a Foreign pointer and turn into a Gloss picture
    {-# NOINLINE rawData #-}
    rawData     = let (Array _ adata)   = arrPixels
                      ((),ptr)          = ptrsOfArrayData adata
                  in
                  unsafePerformIO       $ newForeignPtr_ (castPtr ptr)

    pic         = G.bitmapOfForeignPtr
                      size size                 -- raw image size
                      rawData                   -- the image data
                      False                     -- don't cache this in texture memory

    -- Zoom the image so we get a bigger window.
    zoom'  = fromIntegral zoom


-- Main -----------------------------------------------------------------------
frame :: Render -> Size -> Zoom -> Float -> G.Picture
frame render size zoom time = G.scale zoom' zoom' pic
  where
    -- Scale the time to be the phi value of the animation. The action seems to
    -- slow down at increasing phi values, so we increase phi faster as time
    -- moves on.
    x           = 1 + (time ** 1.5) * 0.005

    -- lift to a singleton array, else we would generate new code with the
    -- constant embedded at every frame
    phi         = A.fromList Z [pi / x]

    -- Compute the image
    arrPixels   = render phi

    -- Wrap the array data in a Foreign pointer and turn into a Gloss picture
    {-# NOINLINE rawData #-}
    rawData     = let (Array _ adata)   = arrPixels
                      ((),ptr)          = ptrsOfArrayData adata
                  in
                  unsafePerformIO       $ newForeignPtr_ (castPtr ptr)

    pic         = G.bitmapOfForeignPtr
                      size size                 -- raw image size
                      rawData                   -- the image data
                      False                     -- don't cache this in texture memory

    -- Zoom the image so we get a bigger window.
    zoom'  = fromIntegral zoom


-- Main -----------------------------------------------------------------------
frame render size zoom time = G.scale zoom' zoom' pic
  where
    -- Scale the time to be the phi value of the animation. The action seems to
    -- slow down at increasing phi values, so we increase phi faster as time
    -- moves on.
    x           = 1 + (time ** 1.5) * 0.005

    -- lift to a singleton array, else we would generate new code with the
    -- constant embedded at every frame
    phi         = A.fromList Z [pi / x]

    -- Compute the image
    arrPixels   = render phi

    -- Wrap the array data in a Foreign pointer and turn into a Gloss picture
    {-# NOINLINE rawData #-}
    rawData     = let (Array _ adata)   = arrPixels
                      ((),ptr)          = ptrsOfArrayData adata
                  in
                  unsafePerformIO       $ newForeignPtr_ (castPtr ptr)

    pic         = G.bitmapOfForeignPtr
                      size size                 -- raw image size
                      rawData                   -- the image data
                      False                     -- don't cache this in texture memory

    -- Zoom the image so we get a bigger window.
    zoom'  = fromIntegral zoom


-- Main -----------------------------------------------------------------------