packages feed

reanimate-1.1.5.0: src/Reanimate/Povray.hs

{-# 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)