content: {-# LANGUAGE OverloadedStrings #-}
  {-|
    [POV-Ray](http://povray.org/) (the Persistance of Vision Raytracer) is a
    scriptable raytracer. All POV-Ray functions are cached and will reuse images
    when scripts stay the same.
  
    The functions come in two versions, for example 'povray' and 'povray''. The
    versions without an apostrophe character yield a 'Tree'. The versions with a
    final apostrophe character yield a 'FilePath' of a PNG file containing the
    resulting image.
  
    The functions differ in their use of the POV-Ray @+W@ (width), @+H@ (height)
    and @+A@ or @-A@ (anti-aliasing) switches, as set out below. Resolutions are
    \'width x height\'.
  
    Example of use:
  
    > povray args script
  
    where @args@ is a list of other POV-Ray command-line switches (if any), and
    @script@ is a POV-Ray scene description specified in the POV-Ray /scene/
    /description language/.
  -}
  module Reanimate.Povray
    ( povray
    , povrayQuick
    , povraySlow
    , povrayExtreme
    , povray'
    , povrayQuick'
    , povraySlow'
    , povrayExtreme'
    ) where
  
  import           Data.Hashable              (Hashable (hash))
  import           Data.Text                  (Text)
  import qualified Data.Text                  as T (concat, pack)
  import qualified Data.Text.IO               as T (writeFile)
  import           Graphics.SvgTree           (Tree)
  import           POVRay                     (runPOVRay)
  import           Reanimate.Cache            (cacheFile, encodeInt)
  import           Reanimate.Constants        (screenHeight, screenWidth)
  import           Reanimate.Parameters       (pNoExternals)
  import           Reanimate.Raster           (mkImage)
  import           Reanimate.Svg.Constructors (mkText)
  import           System.FilePath            (replaceExtension, (<.>))
  import           System.IO.Unsafe           (unsafePerformIO)
  
  
  
  povrayRaw :: [String] -> Text -> Tree
  povrayRaw args script =
    unsafePerformIO $ mkPovrayImage args script
  
  povrayRaw' :: [String] -> Text -> FilePath
  povrayRaw' args script =
    unsafePerformIO $ mkPovrayImage' args script
  
  -- | Run the POV-Ray raytracer with a default resolution of 320x180
  --   and antialiasing enabled. The resulting image is scaled to fit
  --   the screen exactly.
  povray :: [String] -> Text -> Tree
  povray args = povrayRaw (["+H180", "+W320", "+A"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 320x180
  --   and antialiasing enabled. The FilePath points to a PNG file
  --   containing the resulting image.
  povray' :: [String] -> Text -> FilePath
  povray' args = povrayRaw' (["+H180", "+W320", "+A"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 320x180
  --   but without antialiasing. The resulting image is scaled to fit
  --   the screen exactly.
  povrayQuick :: [String] -> Text -> Tree
  povrayQuick args = povrayRaw (["+H180", "+W320"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 320x180
  --   but without antialiasing. The FilePath points to a PNG file
  --   containing the resulting image.
  povrayQuick' :: [String] -> Text -> FilePath
  povrayQuick' args = povrayRaw' (["+H180", "+W320"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 2560x1440
  --   and antialiasing enabled. The resulting image is scaled to fit
  --   the screen exactly.
  povraySlow :: [String] -> Text -> Tree
  povraySlow args = povrayRaw (["+H1440", "+W2560", "+A"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 2560x1440
  --   and antialiasing enabled. The FilePath points to a PNG file
  --   containing the resulting image.
  povraySlow' :: [String] -> Text -> FilePath
  povraySlow' args = povrayRaw' (["+H1440", "+W2560", "+A"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 3840x2160
  --   and antialiasing enabled. The resulting image is scaled to fit
  --   the screen exactly.
  povrayExtreme :: [String] -> Text -> Tree
  povrayExtreme args = povrayRaw (["+H2160", "+W3840", "+A"] ++ args)
  
  -- | Run the POV-Ray raytracer with a default resolution of 3840x2160
  --   and antialiasing enabled. The FilePath points to a PNG file
  --   containing the resulting image.
  povrayExtreme' :: [String] -> Text -> FilePath
  povrayExtreme' args = povrayRaw' (["+H2160", "+W3840", "+A"] ++ args)
  
  mkPovrayImage :: [String] -> Text -> IO Tree
  mkPovrayImage _ script | pNoExternals = pure $ mkText script
  mkPovrayImage args script =
    mkImage screenWidth screenHeight <$> mkPovrayImage' args script
  
  mkPovrayImage' :: [String] -> Text -> IO FilePath
  mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled"
  mkPovrayImage' args script = cacheFile template $ \target -> do
    let pov_file = replaceExtension target "pov"
        otherArgs = ["-D", "+UA", "+I" ++ pov_file, "+O" ++ target]
    T.writeFile pov_file script
    runPOVRay $ args ++ otherArgs
   where
    template = encodeInt (hash key) <.> "png"
    key = T.concat (script:map T.pack args)
  