{-# LANGUAGE BangPatterns #-} import Graphics.UI.GLUT import Data.IORef import Data.Array.IO hiding (range) import System.Console.GetOpt import System.Environment (getArgs) import Bindings import FracState import FracComp inializeScreen opts@Options{size=Sz w h} = do (progname,_) <- getArgsAndInitialize initialDisplayMode $= [DoubleBuffered] lineSmooth $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) createWindow "HFractal" windowSize $= Size (fromIntegral (w-2)) (fromIntegral (h-1)) --clearColor $= Color4 0 0 0 0 matrixMode $= Projection ortho2D 0.0 (fromIntegral (w-1)) 0.0 (fromIntegral (h-1)) matrixMode $= Modelview 0 setCallBacks opts@Options{size=s@(Sz w h), ms=state} = do --Create the state and pixel array ms <- newIORef state pixarr <- newArray (0, w*h-1) 0.0 :: IO Pix --Set the callbacks reshapeCallback $= Just (reshape opts) idleCallback $= Just idle keyboardMouseCallback $= Just (keyboardMouse ms) displayCallback $= display ms s pixarr ---------------------------------------- --Display Callback and related functions ---------------------------------------- display ms sz@(Sz w h) pixarr = do clear [ColorBuffer] loadIdentity Mandstate{xmid=x, ymid=y, range=r, colourmul=cm} <- get ms compPoints x y r sz pixarr preservingMatrix $ do renderPrimitive Points $ displayPix sz cm pixarr swapBuffers 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 ----------------------------------------- idle :: IO () idle = do postRedisplay Nothing 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 key state _ _ = do keyboardAct ms key state ----------------------------------------- --Option Parsing and Main loop ---------------------------------------- zeroState, state1 :: Mandstate zeroState = Mandstate {xmid = 0.0, ymid = 0.0, range = 2.0, colourmul = 0.05} state1 = Mandstate {xmid = 0.001643721971153, ymid = 0.822467633298876, range = 0.05, colourmul = 0.0625} state = state1 defOpts = Options {size=Sz 400 400, ms=state} --TODO: Tidy up the option parser with Data.Accessor(.Template) options :: [OptDescr (Options -> Options)] options = [ Option ['w'] ["width"] (ReqArg (\x opt -> opt {size = sx (size opt) (r x)} ) "WIDTH") "Set width of rendering window", Option ['h'] ["height"] (ReqArg (\y opt -> opt {size = sy (size opt) (r y)} ) "HEIGHT") "Set height of rendering window"] where --Options ['x'] ["x-mid"] (NoArg (\x opt -> opt { ms {xmid = read x} })) sx (Sz x y) x' = (Sz x' y) sy (Sz x y) y' = (Sz x y') r = read 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 [OPTION...]" main :: IO() main = do opts <- getOpts =<< getArgs inializeScreen opts setCallBacks opts mainLoop