GLUT-2.7.0.13: examples/RedBook4/PolyOff.hs
{-
PolyOff.hs (adapted from polyoff.c which is (c) Silicon Graphics, Inc.)
Copyright (c) Sven Panne 2002-2018 <svenpanne@gmail.com>
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