{-# LANGUAGE BangPatterns #-} import Graphics.UI.GLUT import Data.IORef import Data.Array.IO hiding (range) import System.Console.GetOpt import System.Environment (getArgs) import Data.Accessor import Bindings import FracState import FracComp inializeScreen opts@(Options (Sz w h) _) = do (progname,_) <- getArgsAndInitialize initialDisplayMode $= [DoubleBuffered] lineSmooth $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) createWindow "HFractal" windowSize $= Size (fromIntegral (w-2)) (fromIntegral (h-1)) reshapeCallback $= Just (reshape opts) setCallBacks opts@(Options s@(Sz w h) state) = do --Create the state and pixel array ms <- newIORef state pixarr <- newArray (0, w*h-1) 0.0 :: IO Pix --Deal with the window size matrixMode $= Projection ortho2D 0.0 (fromIntegral (w-1)) 0.0 (fromIntegral (h-1)) matrixMode $= Modelview 0 --Set the callbacks keyboardMouseCallback $= Just (keyboardMouse ms s) displayCallback $= display ms s pixarr ---------------------------------------- --Display Callback and related functions ---------------------------------------- display :: (HasGetter g) => g Mandstate -> Sz -> Pix -> IO () display ms sz@(Sz w h) pixarr = do clear [ColorBuffer] loadIdentity (Mandstate x y r cm mi) <- get ms --Get state compPoints x y r mi sz pixarr --Compute escape iterations for this state preservingMatrix $ do renderPrimitive Points $ displayPix sz cm pixarr swapBuffers --Takes the array with escape iterations (+ smoothing) and displays using --the colour function defined in FracComp displayPix :: Sz -> Double -> IOUArray Int Double -> IO () displayPix sz@(Sz width height) cm pixarr = go 0 0 where go !x !y | y == height = return () | x == width = go 0 (y+1) | otherwise = do dk <- readArray pixarr (x + y*width) color (colourMand dk cm) vertex $ Vertex2 (fromIntegral x) (fromIntegral y :: GLfloat) go (x+1) y ----------------------------------------- --Other Callbacks ----------------------------------------- reshape :: Options -> Size -> IO () reshape opts s'@(Size w h) = do viewport $= (Position 0 0, s') --setCallBacks opts{size_=Sz (fromIntegral w) (fromIntegral h)} --Reset the callbacks so that the pixarr is recreated postRedisplay Nothing keyboardMouse ms s key state _ pos = do keyboardMouseAct ms s key state pos postRedisplay Nothing ----------------------------------------- --Option Parsing and Main loop ---------------------------------------- --Some interesting starting positions zeroState, state0, state1, state2 :: Mandstate zeroState = Mandstate 0.0 0.0 2.0 0.05 500 state0 = Mandstate (-0.14076572210832694) 0.8510989379408804 1.0 0.05 5000 state1 = Mandstate 0.001643721971153 0.822467633298876 0.05 0.0625 500 state2 = Mandstate 0.35473015182773904 9.541013313560959e-2 0.0002 0.0625 5000 state = state1 defOpts = Options (Sz 500 500) state options :: [OptDescr (Options -> Options)] options = [ Option ['w'] ["width"] (ReqArg (\w -> size^:wi^=(read w)) "Window width") "Set width of rendering window", Option ['h'] ["height"] (ReqArg (\h -> size^:hi^=(read h)) "Window height") "Set height of rendering window", Option ['x'] ["x-mid"] (ReqArg (\x -> ms^:xmid^=(read x)) "Real(z)") "Set the real part of the initial z (double)", Option ['y'] ["y-mid"] (ReqArg (\y -> ms^:ymid^=(read y)) "Imag(z)") "Set the imaginary part of the inital z (double)", Option ['i'] ["maxiter"] (ReqArg (\i -> ms^:maxiter^=(read i)) "Max iterations") "Maximum iterations until escape (int)", Option ['z'] ["zoom"] (ReqArg (\z -> ms^:range^=(read z)) "Zoom") "Level of zoom (double)"] getOpts :: [String] -> IO Options getOpts argv = case getOpt Permute options argv of (o, [], []) -> return $ foldl (flip ($)) defOpts o (_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options)) where header = "Usage: hfractal [OPTIONS...] [+RTS -N{cores}]" main :: IO() main = do opts <- getOpts =<< getArgs inializeScreen opts setCallBacks opts mainLoop