{- PolyOff.hs (adapted from polyoff.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2006 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates polygon offset to draw a shaded polygon and its wireframe counterpart without ugly visual artifacts ("stitching"). -} import Control.Monad ( when ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess), exitFailure ) import Graphics.UI.GLUT data State = State { spinX, spinY :: IORef GLfloat, tDist :: IORef GLfloat, polyFactor :: IORef GLfloat, polyUnits :: IORef GLfloat } makeState :: IO State makeState = do x <- newIORef 0 y <- newIORef 0 t <- newIORef 0 f <- newIORef 1 u <- newIORef 1 return $ State { spinX = x, spinY = y, tDist = t, polyFactor = f, polyUnits = u } -- display draws two spheres, one with a gray, diffuse material, the other -- sphere with a magenta material with a specular highlight. display :: State -> DisplayList -> DisplayCallback display state sphereList = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do t <- get (tDist state) translate (Vector3 0 0 t) x <- get (spinX state) rotate x (Vector3 1 0 0) y <- get (spinY state) rotate y (Vector3 0 1 0) materialAmbientAndDiffuse Front $= Color4 0.8 0.8 0.8 1 materialSpecular Front $= Color4 0 0 0 1 materialShininess Front $= 0 lighting $= Enabled light (Light 0) $= Enabled polygonOffsetFill $= Enabled f <- get (polyFactor state) u <- get (polyUnits state) polygonOffset $= (f, u) callList sphereList polygonOffsetFill $= Disabled lighting $= Disabled light (Light 0) $= Disabled color (Color3 1 1 (1 :: GLfloat)) polygonMode $= (Line, Line) callList sphereList polygonMode $= (Fill, Fill) flush -- specify initial properties -- create display list with sphere -- initialize lighting and depth buffer gfxinit :: IO DisplayList gfxinit = do clearColor $= Color4 0 0 0 1 sphereList <- defineNewList Compile $ renderObject Solid (Sphere' 1 20 12) depthFunc $= Just Less ambient (Light 0) $= Color4 0 0 0 1 diffuse (Light 0) $= Color4 1 1 1 1 specular (Light 0) $= Color4 1 1 1 1 position (Light 0) $= Vertex4 1 1 1 0 lightModelAmbient $= Color4 0.2 0.2 0.2 1 return sphereList reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 (fromIntegral w / fromIntegral h) 1 10 matrixMode $= Modelview 0 loadIdentity lookAt (Vertex3 0 0 5) (Vertex3 0 0 0) (Vector3 0 1 0) incSpin :: IORef GLfloat -> IO () incSpin spinRef = do let wrap n s = if s > n then s - n else s spinRef $~ (wrap 360 . (+ 5)) postRedisplay Nothing incDist :: State -> GLfloat -> IO () incDist state inc = do newDist <- fmap (+ inc) $ get (tDist state) when (-5 <= newDist && newDist <= 4) $ do tDist state $= newDist postRedisplay Nothing incPoly :: String -> IORef GLfloat -> GLfloat -> IO () incPoly name polyRef inc = do polyRef $~ (+ inc) p <- get polyRef putStrLn (name ++ " is " ++ show p) postRedisplay Nothing keyboardMouse :: State -> KeyboardMouseCallback keyboardMouse state k Down _ _ = case k of (MouseButton LeftButton) -> incSpin (spinX state) (MouseButton MiddleButton) -> incSpin (spinY state) (MouseButton RightButton) -> exitWith ExitSuccess (Char 't') -> incDist state 0.5 (Char 'T') -> incDist state (-0.5) (Char 'F') -> incPoly "polyFactor" (polyFactor state) 0.1 (Char 'f') -> incPoly "polyFactor" (polyFactor state) (-0.1) (Char 'U') -> incPoly "polyUnits" (polyUnits state) 1 (Char 'u') -> incPoly "polyUnits" (polyUnits state) (-1) _ -> return () keyboardMouse _ _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) when (version == (1,0)) $ do putStrLn "This program demonstrates a feature which is not in OpenGL Version 1.0." putStrLn "If your implementation of OpenGL Version 1.0 has the right extensions," putStrLn "you may be able to modify this program to make it run." exitFailure state <- makeState sphereList <- gfxinit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse state) displayCallback $= display state sphereList mainLoop