diff --git a/reanimate.cabal b/reanimate.cabal index 79eabfe..d1ff354 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -111,6 +111,7 @@ library Reanimate.Scene.Sprite Reanimate.Scene.Object Detach + POVRay autogen-modules: Paths_reanimate if flag(no-hgeometry) cpp-options: -DNO_HGEOMETRY diff --git a/src/Reanimate/Cache.hs b/src/Reanimate/Cache.hs index e39800e..0144ce6 100644 --- a/src/Reanimate/Cache.hs +++ b/src/Reanimate/Cache.hs @@ -104,6 +104,6 @@ encodeInt i = worker (fromIntegral i) 60 worker key sh | sh < 0 = [] | otherwise = - case (key `shiftR` sh) `mod` 64 of - idx -> alphabet !! fromIntegral idx : worker key (sh-6) - alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+$" + case (key `shiftR` sh) `mod` 32 of + idx -> alphabet !! fromIntegral idx : worker key (sh-5) + alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" diff --git a/src/Reanimate/Driver/Check.hs b/src/Reanimate/Driver/Check.hs index 33a2d61..66ae5c4 100644 --- a/src/Reanimate/Driver/Check.hs +++ b/src/Reanimate/Driver/Check.hs @@ -11,6 +11,7 @@ import Control.Exception (SomeException, handle) import Control.Monad (forM_) import Data.Maybe (fromMaybe, listToMaybe) import Data.Version (Version (Version), parseVersion, showVersion) +import POVRay (povrayApp) import Reanimate.Driver.Magick (magickCmd) import Reanimate.Misc (runCmd_) import System.Console.ANSI.Codes @@ -88,7 +89,7 @@ hasDvisvgm :: IO (Either String String) hasDvisvgm = hasProgram "dvisvgm" hasPovray :: IO (Either String String) -hasPovray = hasProgram "povray" +hasPovray = hasProgram povrayApp hasFFmpeg :: IO (Either String String) hasFFmpeg = checkMinVersion minVersion <$> ffmpegVersion diff --git a/src/Reanimate/Povray.hs b/src/Reanimate/Povray.hs index 14b76eb..76cbb46 100644 --- a/src/Reanimate/Povray.hs +++ b/src/Reanimate/Povray.hs @@ -14,18 +14,13 @@ module Reanimate.Povray , povrayExtreme' ) where -import Data.Hashable (Hashable (hash)) import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Text.IO as T import Graphics.SvgTree (Tree) -import Reanimate.Cache (cacheFile, encodeInt) +import POVRay (mkPovrayImage') import Reanimate.Constants (screenHeight, screenWidth) -import Reanimate.Misc (requireExecutable, runCmd) 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 @@ -88,14 +83,3 @@ 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 - exec <- requireExecutable "povray" - let pov_file = replaceExtension target "pov" - T.writeFile pov_file script - runCmd exec (args ++ ["-D","+UA", pov_file, "+o"++target]) - where - template = encodeInt (hash key) <.> "png" - key = T.concat (script:map T.pack args) diff --git a/unix/POVRay.hs b/unix/POVRay.hs new file mode 100644 index 0000000..ae6d1e8 --- /dev/null +++ b/unix/POVRay.hs @@ -0,0 +1,27 @@ +module POVRay + ( povrayApp + , mkPovrayImage' + ) 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 Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Misc (requireExecutable, runCmd) +import Reanimate.Parameters (pNoExternals) +import System.FilePath (replaceExtension, (<.>)) + +povrayApp :: String +povrayApp = "povray" + +mkPovrayImage' :: [String] -> Text -> IO FilePath +mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" +mkPovrayImage' args script = cacheFile template $ \target -> do + exec <- requireExecutable povrayApp + let pov_file = replaceExtension target "pov" + T.writeFile pov_file script + runCmd exec (args ++ ["-D", "+UA", "+I" ++ pov_file, "+o" ++ target]) + where + template = encodeInt (hash key) <.> "png" + key = T.concat (script:map T.pack args) diff --git a/windows/POVRay.hs b/windows/POVRay.hs new file mode 100644 index 0000000..1262a42 --- /dev/null +++ b/windows/POVRay.hs @@ -0,0 +1,66 @@ +module POVRay + ( povrayApp + , mkPovrayImage' + ) 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 Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Misc (requireExecutable, runCmd) +import Reanimate.Parameters (pNoExternals) +import System.FilePath (replaceExtension, (<.>)) +import System.IO (hClose, hPutStrLn) +import System.IO.Temp (withSystemTempFile) + +povrayApp :: String +povrayApp = "pvengine64" -- Assumes 64 bit Windows + +mkPovrayImage' :: [String] -> Text -> IO FilePath +mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" +mkPovrayImage' args script = cacheFile template $ \target -> do + exec <- requireExecutable povrayApp + let pov_file = replaceExtension target "pov" + exec' = '"' : exec ++ "\"" -- Wrap exec in "" because the path is likely + -- to includes spaces + otherArgs = [ "-D" + , "+UA" + , "+I" ++ pov_file + , "+O" ++ target + , "/EXIT" -- Note [/EXIT special command-line option] + ] + command = concatMap (' ':) (exec' : args ++ otherArgs) + T.writeFile pov_file script + -- Note [Use of a batch file] + withSystemTempFile "pvcommand.bat" $ \path h -> do + hPutStrLn h command + hClose h + runCmd path [] + where + template = encodeInt (hash key) <.> "png" + key = T.concat (script:map T.pack args) + +{- +Note [/EXIT special command-line option] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"The /EXIT command tells POV-Ray to perform the render given by the other +command-line options, combined with previously-set options such as internal +command-line settings, INI file, source file, and so forth, and then to exit. By +default, if this switch is not present, POV-Ray for Windows will remain running +after the render is complete. This switch only applies to renders started by +other options on the command-line. It will not affect renders started manually +from within POV-Ray for Windows itself." +source: https://www.povray.org/documentation/view/3.6.1/603/ + +Note [Use of batch file] +~~~~~~~~~~~~~~~~~~~~~~~~ + +POV-Ray for Windows assumes that anything on the command-line that is not a +switch is the name of an INI file. Switches are preceded by a plus or minus. +However, System.Process.createProcess_ wraps all arguments in "". POV_Ray for +Windows appears to interpret a switch wrapped in "" as the name of an INI file. + +The work around used here is to write the POV-Ray command line to a batch file. +-}