packages feed

hfractal-0.1.0: Hfractal.hs

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