{-# OPTIONS_GHC -Wall #-} module Vis.Camera ( Camera0(..) , Camera(..) , makeCamera , setCamera , cameraMotion , cameraKeyboardMouse ) where import Graphics.UI.GLUT ( GLdouble, GLint , Vector3(..), Vertex3(..) , Position(..), MouseButton(..), Key(..), KeyState(..) ) import qualified Graphics.UI.GLUT as GLUT import SpatialMath ( V3(..) ) data Camera0 = Camera0 { phi0 :: GLdouble , theta0 :: GLdouble , rho0 :: GLdouble } deriving Show data Camera = Camera { phi :: GLdouble , theta :: GLdouble , rho :: GLdouble , pos :: V3 GLdouble , ballX :: GLint , ballY :: GLint , leftButton :: GLint , rightButton :: GLint , middleButton :: GLint } makeCamera :: Camera0 -> Camera makeCamera camera0 = Camera { phi = phi0 camera0 , theta = theta0 camera0 , rho = rho0 camera0 , pos = V3 0 0 0 , ballX = (-1) , ballY = (-1) , leftButton = 0 , rightButton = 0 , middleButton = 0 } setCamera :: Camera -> IO () setCamera camera = GLUT.lookAt (Vertex3 xc yc zc) (Vertex3 x0 y0 z0) (Vector3 0 0 (-1)) where V3 x0 y0 z0 = pos camera phi' = phi camera theta' = theta camera rho' = rho camera xc = x0 + rho'*cos(phi'*pi/180)*cos(theta'*pi/180) yc = y0 + rho'*sin(phi'*pi/180)*cos(theta'*pi/180) zc = z0 - rho'*sin(theta'*pi/180) cameraMotion :: Camera -> Position -> Camera cameraMotion (Camera phi0' theta0' rho0' (V3 x0 y0 z0) bx by lb rb mb) (Position x y) = Camera nextPhi nextTheta rho0' nextPos nextBallX nextBallY lb rb mb where deltaX | bx == -1 = 0 | otherwise = fromIntegral (x - bx) deltaY | by == -1 = 0 | otherwise = fromIntegral (y - by) deltaZ | by == -1 = 0 | otherwise = fromIntegral (y - by) nextTheta' | deltaY + theta0' > 80 = 80 | deltaY + theta0' < -80 = -80 | otherwise = deltaY + theta0' nextX = x0 + 0.003*rho0'*( -sin(phi0'*pi/180)*deltaX - cos(phi0'*pi/180)*deltaY) nextY = y0 + 0.003*rho0'*( cos(phi0'*pi/180)*deltaX - sin(phi0'*pi/180)*deltaY) nextZ = z0 - 0.001*rho0'*deltaZ (nextPhi, nextTheta) = if lb == 1 then (phi0' + deltaX, nextTheta') else (phi0', theta0') nextPos | rb == 1 = V3 nextX nextY z0 | mb == 1 = V3 x0 y0 nextZ | otherwise = V3 x0 y0 z0 nextBallX = x nextBallY = y cameraKeyboardMouse :: Camera -> Key -> KeyState -> Camera cameraKeyboardMouse camera key keyState = camera {rho = newRho, leftButton = lb, rightButton = rb, middleButton = mb, ballX = bx, ballY = by} where (lb, reset0) = case (key, keyState) of (MouseButton LeftButton, Down) -> (1, True) (MouseButton LeftButton, Up) -> (0, False) _ -> (leftButton camera, False) (rb, reset1) = case (key, keyState) of (MouseButton RightButton, Down) -> (1, True) (MouseButton RightButton, Up) -> (0, False) _ -> (rightButton camera, False) (mb, reset2) = case (key, keyState) of (MouseButton MiddleButton, Down) -> (1, True) (MouseButton MiddleButton, Up) -> (0, False) _ -> (middleButton camera, False) (bx,by) = if reset0 || reset1 || reset2 then (-1,-1) else (ballX camera, ballY camera) newRho = case (key, keyState) of (MouseButton WheelUp, Down) -> 0.9 * (rho camera) (MouseButton WheelDown, Down) -> 1.1 * (rho camera) (Char 'e', Down) -> 0.9 * (rho camera) (Char 'q', Down) -> 1.1 * (rho camera) _ -> rho camera