packages feed

reactive-glut-0.0.1: src/FRP/Reactive/GLUT/SimpleGfx.hs

{-# OPTIONS_GHC -Wall #-}

module FRP.Reactive.GLUT.SimpleGfx
  ( initGfx, glwrap, windowPoint
  -- remove later
  , drawBox
  ) where

import Graphics.UI.GLUT
-- import Graphics.Rendering.OpenGL as GL

windowWidth, windowHeight :: GLint
windowWidth = 800 -- physical pixels
windowHeight = 600 -- physical pixels

canvasMinX, canvasMaxX, canvasMinY, canvasMaxY :: Double
canvasMaxX =  400 -- logical units
canvasMinX = -400 -- logical units
canvasMaxY =  300 -- logical units
canvasMinY = -300 -- logical units

canvasFarZ, canvasNearZ :: GLclampd
canvasFarZ =  4000
canvasNearZ = -4000

-- Initialize GL graphics
initGfx :: String -> IO ()
initGfx title = do
  -- Glut Part
  getArgsAndInitialize
  initialWindowSize $= (Size windowWidth windowHeight)
  initialDisplayMode $= [DoubleBuffered, RGBAMode]
  createWindow title
  -- OpenGL Part
  shadeModel $= Smooth
  lineSmooth $= Enabled

  lighting $= Enabled
  -- Needs to be disabled for fieldtrip
  -- colorMaterial $= Just (Front,AmbientAndDiffuse)
  light (Light 0) $= Enabled

  -- Enable the following if non-uniform scaling will occur
  normalize $= Enabled
  -- Enable the following if only uniform scaling will occur
  -- rescaleNormal $= Enabled

  -- Set the light up at an infinite distance behind the camera
  position (Light 0) $= (Vertex4 0.0 0.0 1.0 0.0)
  ambient (Light 0) $= (Color4 0.0 0.0 0.0 1.0)
  diffuse (Light 0) $= (Color4 1.0 1.0 1.0 1.0)
  specular (Light 0) $= (Color4 1.0 1.0 1.0 1.0)

  -- Some simple defaults here.
  materialSpecular (Front) $= (Color4 1.0 1.0 1.0 1.0)
  materialEmission (Front) $= (Color4 0.0 0.0 0.0 1.0)
  materialShininess (Front) $= 70.0

  blend $= Enabled
  blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
  lineWidth $= 1.5
  clearColor $= Color4 0 0 0 0
  pointSmooth $= Enabled
  -- pointSize $= 5.0
  clearDepth $= canvasFarZ
  depthRange $= (canvasNearZ, canvasFarZ)
  depthFunc $= Just Lequal
  matrixMode $= Projection
  loadIdentity
  ortho canvasMinX canvasMaxX canvasMinY canvasMaxY canvasNearZ canvasFarZ
  matrixMode $= Modelview 0
  loadIdentity

-- | Convert a window position to a logical X,Y.  Logical zero is at the
-- origin, and [size??].
-- 
-- TODO: fix to work with variable window size.
windowPoint :: Position -> IO (Double, Double)
windowPoint (Position x y) = return $
 let pixToLog p minP maxP l u = 
       let p0to1 = (realToFrac $ p-minP)/(realToFrac $ maxP-minP)
       in (p0to1 * (u-l)) + l
 in (pixToLog x 0 (windowWidth-1) canvasMinX canvasMaxX,
     -(pixToLog y 0 (windowHeight-1) canvasMinY canvasMaxY))

-- | Wrap an OpenGL rendering action, to clear the frame-buffer before
-- swap buffers afterward.
glwrap :: IO () -> IO ()
glwrap act = do clearScreen (0.0,0.0,0.0)
                -- putStrLn "glwrap"
                act
                swapBuffers

clearScreen :: (GLdouble, GLdouble, GLdouble) -> IO()
clearScreen (r,g,b) = do
  clearColor $= Color4 (realToFrac r) (realToFrac g) (realToFrac b) 0
  clear [ColorBuffer, DepthBuffer]


vertexPF :: VertexComponent a => (a,a) -> IO ()
vertexPF = vertex . (uncurry Vertex2)

drawBox :: (MatrixComponent c, Fractional c) => (c, c) -> IO ()
drawBox (centerX,centerY) = preservingMatrix $ do
  translate $ Vector3 centerX centerY 0.0
  renderPrimitive Polygon (mapM_ vertexPF [
      (-10.0::GLdouble ,-10.0),
      (-10.0,10.0),
      (10.0,10.0),
      (10.0,-10.0) ] )