HRay visual main program, built with Gtk2Hs intended for usage with the other modules in the HRay package author: Kenneth Hoste, 2004-2005 part of a masters thesis at the University of Ghent, Belgium ========================================================================== > import Graphics.UI.Gtk hiding (Graphics.UI.Gtk.Gdk.Enums.Solid,Graphics.UI.Gtk.General.Structs.Color) > import Data.IORef (newIORef,readIORef,writeIORef) > import Data.Array (Array, (!), listArray) > import Maybe (isNothing) > import PixBufExtras (pixbufSetPixelsRGB8) > import HRayEngine (Scene(Scene)) > import HRayOutput (getRenderTime, getImage) > import HRayParser (RenderDescr(RenderDescr), readDescr) > import Directory (doesFileExist) > import System.CPUTime (getCPUTime) -------------------- | Reading a scene | -------------------- > loadThisScene :: String -> IO (Maybe RenderDescr) > loadThisScene file = do > exists <- doesFileExist file > case exists of > True -> do > fileContent <- readFile file > return (Just (readDescr fileContent)) > False -> return Nothing ------------------------- | Handling click events | ------------------------ loading a scene > loadScene :: String -> Label -> Label -> Label -> IO (Maybe RenderDescr) > loadScene "" messLabel descrLabel renderTimeLabel = do > labelSetText messLabel "\nNo scene loaded.\n" > labelSetText descrLabel "\nScene description:\n\n Resolution: \n Objects: \n Lights: \n" > labelSetText renderTimeLabel "\nRender time:\n\n \n" > return Nothing > loadScene file messLabel descrLabel renderTimeLabel = do > renderDescr <- loadThisScene file > labelSetText renderTimeLabel "\nRender time:\n\n \n" > case renderDescr of > Nothing -> do > labelSetText messLabel "\nNo such file.\n" > labelSetText descrLabel "\nScene description:\n\n Resolution: \n Objects: \n Lights: \n" > (Just (RenderDescr (rx,ry) depth (Scene _ _ objects lights)) ) -> do > labelSetText messLabel "\nScene loaded.\n" > labelSetText descrLabel ("\nScene description:\n\n Resolution: "++(show rx)++"x"++ > (show ry)++"\n # Objects: "++(show (length objects))++"\n # Lights: "++ > (show (length lights))++"\n") > return renderDescr setting up a pixbuf with a Color array > pixbufSetPixelsRGB8FromArray :: Int -> Pixbuf -> Array Int (Int,Int,Int) -> IO() > pixbufSetPixelsRGB8FromArray w pixbuf arr = > pixbufSetPixelsRGB8 pixbuf (\x y -> (\ (r,g,b) -> (fromIntegral r, fromIntegral g, fromIntegral b)) $ arr!(y*w+x) ) rendering a scene > renderScene :: (Maybe RenderDescr) -> Label -> IO Pixbuf > renderScene (Just (RenderDescr res@(rx,ry) depth scene)) descrLabel = do > let colorList = map (\ (r,g,b) -> (round (r*255),round (g*255),round (b*255))) $ getImage depth res scene > colorArray = listArray (0,rx*ry-1) colorList > pixBuf <- pixbufNew ColorspaceRgb False 8 rx ry > pixbufSetPixelsRGB8FromArray rx pixBuf colorArray > return pixBuf --------------------------- | Handling closure events | --------------------------- returning 'False' results in destroys the window (and throws a destroy-event) > deleteEvent :: Event -> IO Bool > deleteEvent _ = do return False what should happen when the window is being closed > destroyEvent :: IO() > destroyEvent = do mainQuit -------------------- | : : : MAIN : : : | -------------------- > main :: IO() > main = do initializing GUI > initGUI setting up new window > window <- windowNew > onDelete window deleteEvent > onDestroy window destroyEvent > windowSetTitle window "HRay - a Haskell raytracer" creating a place to show the rendered image > scrollWindow <- scrolledWindowNew Nothing Nothing > containerSetBorderWidth scrollWindow 10 > image <- imageNewFromFile "default.png" > scrolledWindowAddWithViewport scrollWindow image > widgetSetSizeRequest scrollWindow 800 600 creating the control panel > controlPanel <- vBoxNew False 2 > containerSetBorderWidth controlPanel 10 setting up the file entry box > entry <- entryNew > entrySetWidthChars entry 20 setting up the load button > loadButton <- buttonNewWithLabel "Load scene" setting up the message label > messageLabel <- labelNew (Just "\nNo scene loaded.\n") setting up the render button > renderButton <- buttonNewWithLabel "Render scene" setting up the scene description label > descrLabel <- labelNew (Just "\nScene description:\n\n Resolution: \n Objects: \n Lights: \n") setting up the render time label > renderTimeLabel <- labelNew (Just "\nRender time:\n\n \n") preparing scene > renderDescrRef <- newIORef Nothing setting click actions > onClicked loadButton $ do > fileStr <- (entryGetText entry) > renderDescr <- loadScene fileStr messageLabel descrLabel renderTimeLabel > writeIORef renderDescrRef renderDescr > onClicked renderButton $ do > renderDescr <- readIORef renderDescrRef > let loop = do > n <- eventsPending > if n == 0 then return () else mainIterationDo False >> loop > if isNothing renderDescr then > labelSetMarkupWithMnemonic messageLabel "\nPlease load a scene.\n" > else do > timeBefore <- getCPUTime > labelSetMarkupWithMnemonic messageLabel ("\n"++ > "Rendering scene...\n") > loop > pixBuf <- renderScene renderDescr descrLabel > labelSetText messageLabel "\nScene rendered !\n" > imageSetFromPixbuf image pixBuf > timeAfter <- getCPUTime > labelSetText renderTimeLabel $ "\nRender time:\n\n " ++ > (getRenderTime timeBefore timeAfter) ++ "\n" adding everything to the control panel > boxPackStart controlPanel entry PackNatural 0 > boxPackStart controlPanel loadButton PackNatural 0 > boxPackStart controlPanel messageLabel PackNatural 0 > boxPackStart controlPanel renderButton PackNatural 0 > boxPackStart controlPanel descrLabel PackNatural 0 > boxPackStart controlPanel renderTimeLabel PackNatural 0 adding everything to the window > hBox <- hBoxNew False 2 > boxPackStart hBox scrollWindow PackNatural 0 > boxPackStart hBox controlPanel PackNatural 0 > containerAdd window hBox packing and showing everything > widgetShowAll window wait for events to occure > mainGUI