hglmandel/05_Mandelbulb/YGL.hs

209 lines
5.9 KiB
Haskell
Raw Normal View History

2012-05-15 15:25:50 +00:00
module YGL (
Point
, Scalar
, Point3D
, Function3D
, yMainLoop
, InputMap
, inputMapFromList) where
2012-05-15 13:21:18 +00:00
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
import Data.IORef
import Data.Map ((!))
import qualified Data.Map as Map
2012-05-18 13:26:36 +00:00
-- | A 1D point
2012-05-15 15:25:50 +00:00
type Point = GLfloat
2012-05-18 13:26:36 +00:00
-- | A Scalar value
2012-05-15 15:25:50 +00:00
type Scalar = GLfloat
2012-05-18 13:26:36 +00:00
-- | A 3D Point mainly '(x,y,z)'
2012-05-15 15:25:50 +00:00
data Point3D = Point3D {
xpoint :: Point
, ypoint :: Point
, zpoint :: Point }
2012-05-18 13:26:36 +00:00
class YObject a where
triangles a :: Box3D -> [Points3D]
2012-05-15 15:25:50 +00:00
type Function3D = Point -> Point -> Maybe Point
2012-05-18 13:26:36 +00:00
instance YObject Function3D
triangles = flip getObject3DFromShapeFunction
-- | We decalre the input map type we need here
-- | It is our API
type InputMap worldType = Map.Map UserInput (worldType -> worldType)
data UserInput = Press Char | Ctrl Char | Alt Char | CtrlAlt Char
-- | A displayable world
class DisplayableWorld a where
camera :: a -> Camera
objects :: a -> [YObject]
data Camera = Camera {
position :: Point3D
, direction :: Point3D
, zoom :: Scalar
}
2012-05-15 15:25:50 +00:00
data Camera = Camera {
xcam :: Point
, ycam :: Point
, zcam :: Point
}
data Object3D = [Point3D]
data Box3D = R {
minPoint :: Point3D
maxPoint :: Point3D
}
2012-05-18 13:26:36 +00:00
zero3D = Point3D { xpoint = 0, ypoint = 0, zpoint = 0}
one3D = Point3D { xpoint = 1, ypoint = 1, zpoint = 1}
unityBox = { zero3D, one3D }
2012-05-15 15:25:50 +00:00
-- Given a shape function and a delimited Box3D
-- return a list of Triangles to be displayed
getObject3DFromShapeFunction :: Function3D -> Box3D -> [Point3D]
getObject3DFromShapeFunction shape box =
x <- [xmin..xmax]
y <- [ymin..ymax]
let
neighbors = [(x,y),(x+1,y),(x+1,y+1),(x,y+1)]
-- zs are 3D points with found depth
zs = map (\(u,v) -> (u,v,shape u v)) neighbors
-- ps are 3D opengl points + color value
ps = map (\(u,v,w,c') ->
(u/width,v/height,w/depth)) zs
-- If the point diverged too fast, don't display it
if (and $ map (\(_,_,z) -> z==Nothing) ts)
then []
-- Draw two triangles
-- 3 - 2
-- | / |
-- 0 - 1
else [ps!!0,ps!!1,ps!!2,ps!!0,ps!!2,ps!!3]
where
-- some naming to make it
-- easier to read
xmin = xpoint minPoint box
xmax = xpoint maxPoint box
width = xmax - xmin
ymin = ypoint minPoint box
ymay = ypoint mayPoint box
height = ymax - ymin
zmin = zpoint minPoint box
zmaz = zpoint mazPoint box
depth = zmax - zmin
2012-05-15 13:21:18 +00:00
inputMapFromList = Map.fromList
-- We set our mainLoop function
-- As you can see it is _not_ functional!
-- This can be perceived as BAD.
-- But I wanted to use the imperative GLUT library
-- We have no choice for now.
2012-05-15 15:25:50 +00:00
yMainLoop :: String -- window name
-> InputMap -- the mapping user input / world
-> worldType -- the world state
-> (worldType -> ViewState) -- a function from world state to view
-> IO () -- into IO () for obvious reason
yMainLoop windowTitle
inputActionMap
camera
world
viewFromWorld = do
2012-05-15 13:21:18 +00:00
-- The boilerplate
(progname,_) <- getArgsAndInitialize
initialDisplayMode $=
[WithDepthBuffer,DoubleBuffered,RGBMode]
createWindow windowTitle
depthFunc $= Just Less
windowSize $= Size 500 500
-- The state variables for the world (I know it feels BAD)
worldRef <- newIORef world
-- Action to call when waiting
idleCallback $= Just idle
-- the keyboard will update the world
keyboardMouseCallback $=
Just (keyboardMouse inputActionMap worldRef)
-- We generate one frame using the callback
2012-05-15 15:25:50 +00:00
displayCallback $= display viewFromWorld worldRef
2012-05-15 13:21:18 +00:00
-- We enter the main loop
mainLoop
2012-05-15 15:25:50 +00:00
-- When no user input entered do nothing
2012-05-15 13:21:18 +00:00
idle = postRedisplay Nothing
-- Get User Input
2012-05-15 15:25:50 +00:00
-- both cleaner, terser and more expendable than the preceeding code
2012-05-15 13:21:18 +00:00
keyboardMouse input world state modifiers position =
if modifiers == Down
then
let transformator = input ! (Press state)
in do
w <- get world
world $= (transformator w)
else return ()
-- The function that will display datas
2012-05-15 15:25:50 +00:00
display worldRef getViewFromWorld = do
-- BEWAREA UGLINESS!!!!
-- SHOULD NEVER MODIFY worldRef HERE!!!!
w <- get worldRef
let view = getViewFromWorld w
-- set the background color (dark solarized theme)
clearColor $= Color4 0 0.1686 0.2117 1
clear [ColorBuffer,DepthBuffer]
-- Transformation to change the view
loadIdentity -- reset any transformation
-- tranlate
(x,y) <- get position
translate $ Vector3 x y 0
-- zoom
z <- get zoom
scale z z z
-- rotate
(xangle,yangle,zangle) <- get angle
rotate xangle $ Vector3 1.0 0.0 (0.0::GLfloat)
rotate yangle $ Vector3 0.0 1.0 (0.0::GLfloat)
rotate zangle $ Vector3 0.0 0.0 (1.0::GLfloat)
-- Now that all transformation were made
-- We create the object(s)
t <- get elapsedTime
preservingMatrix $ drawObject (triangles t)
swapBuffers -- refresh screen
2012-05-15 13:21:18 +00:00
-- The function that will display datas
display angle zoom position triangles = do
-- set the background color (dark solarized theme)
clearColor $= Color4 0 0.1686 0.2117 1
clear [ColorBuffer,DepthBuffer]
-- Transformation to change the view
loadIdentity -- reset any transformation
-- tranlate
(x,y) <- get position
translate $ Vector3 x y 0
-- zoom
z <- get zoom
scale z z z
-- rotate
(xangle,yangle,zangle) <- get angle
rotate xangle $ Vector3 1.0 0.0 (0.0::GLfloat)
rotate yangle $ Vector3 0.0 1.0 (0.0::GLfloat)
rotate zangle $ Vector3 0.0 0.0 (1.0::GLfloat)
-- Now that all transformation were made
-- We create the object(s)
t <- get elapsedTime
preservingMatrix $ drawObject (shape w)
swapBuffers -- refresh screen
drawObject shape = do
-- We will print Points (not triangles for example)
renderPrimitive Triangles $ do
2012-05-18 13:26:36 +00:00
mapM_ drawPoint (triangles unityBox shape)
2012-05-15 13:21:18 +00:00
where
2012-05-15 15:25:50 +00:00
drawPoint (x,y,z) = vertex $ Vertex3 x y z