{-# 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 { Camera0 -> GLdouble
phi0 :: GLdouble
                       , Camera0 -> GLdouble
theta0 :: GLdouble
                       , Camera0 -> GLdouble
rho0 :: GLdouble
                       } deriving Int -> Camera0 -> ShowS
[Camera0] -> ShowS
Camera0 -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Camera0] -> ShowS
$cshowList :: [Camera0] -> ShowS
show :: Camera0 -> String
$cshow :: Camera0 -> String
showsPrec :: Int -> Camera0 -> ShowS
$cshowsPrec :: Int -> Camera0 -> ShowS
Show

data Camera = Camera { Camera -> GLdouble
phi :: GLdouble
                     , Camera -> GLdouble
theta :: GLdouble
                     , Camera -> GLdouble
rho :: GLdouble
                     , Camera -> V3 GLdouble
pos :: V3 GLdouble
                     , Camera -> GLint
ballX :: GLint
                     , Camera -> GLint
ballY :: GLint 
                     , Camera -> GLint
leftButton :: GLint
                     , Camera -> GLint
rightButton :: GLint
                     , Camera -> GLint
middleButton :: GLint
                     }

makeCamera :: Camera0 -> Camera
makeCamera :: Camera0 -> Camera
makeCamera Camera0
camera0 = Camera { phi :: GLdouble
phi   = Camera0 -> GLdouble
phi0 Camera0
camera0
                            , theta :: GLdouble
theta = Camera0 -> GLdouble
theta0 Camera0
camera0
                            , rho :: GLdouble
rho   = Camera0 -> GLdouble
rho0 Camera0
camera0
                            , pos :: V3 GLdouble
pos = forall a. a -> a -> a -> V3 a
V3 GLdouble
0 GLdouble
0 GLdouble
0
                            , ballX :: GLint
ballX = (-GLint
1)
                            , ballY :: GLint
ballY = (-GLint
1)
                            , leftButton :: GLint
leftButton = GLint
0
                            , rightButton :: GLint
rightButton = GLint
0
                            , middleButton :: GLint
middleButton = GLint
0
                            }

setCamera :: Camera -> IO ()
setCamera :: Camera -> IO ()
setCamera Camera
camera = Vertex3 GLdouble -> Vertex3 GLdouble -> Vector3 GLdouble -> IO ()
GLUT.lookAt (forall a. a -> a -> a -> Vertex3 a
Vertex3 GLdouble
xc GLdouble
yc GLdouble
zc) (forall a. a -> a -> a -> Vertex3 a
Vertex3 GLdouble
x0 GLdouble
y0 GLdouble
z0) (forall a. a -> a -> a -> Vector3 a
Vector3 GLdouble
0 GLdouble
0 (-GLdouble
1))
  where
    V3 GLdouble
x0 GLdouble
y0 GLdouble
z0 = Camera -> V3 GLdouble
pos Camera
camera
    phi' :: GLdouble
phi'   = Camera -> GLdouble
phi   Camera
camera
    theta' :: GLdouble
theta' = Camera -> GLdouble
theta Camera
camera
    rho' :: GLdouble
rho'   = Camera -> GLdouble
rho   Camera
camera

    xc :: GLdouble
xc = GLdouble
x0 forall a. Num a => a -> a -> a
+ GLdouble
rho'forall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos(GLdouble
phi'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)forall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos(GLdouble
theta'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)
    yc :: GLdouble
yc = GLdouble
y0 forall a. Num a => a -> a -> a
+ GLdouble
rho'forall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin(GLdouble
phi'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)forall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos(GLdouble
theta'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)
    zc :: GLdouble
zc = GLdouble
z0 forall a. Num a => a -> a -> a
- GLdouble
rho'forall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin(GLdouble
theta'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)

cameraMotion :: Camera -> Position -> Camera
cameraMotion :: Camera -> Position -> Camera
cameraMotion (Camera GLdouble
phi0' GLdouble
theta0' GLdouble
rho0' (V3 GLdouble
x0 GLdouble
y0 GLdouble
z0) GLint
bx GLint
by GLint
lb GLint
rb GLint
mb) (Position GLint
x GLint
y) =
  GLdouble
-> GLdouble
-> GLdouble
-> V3 GLdouble
-> GLint
-> GLint
-> GLint
-> GLint
-> GLint
-> Camera
Camera GLdouble
nextPhi GLdouble
nextTheta GLdouble
rho0' V3 GLdouble
nextPos GLint
nextBallX GLint
nextBallY GLint
lb GLint
rb GLint
mb
  where
    deltaX :: GLdouble
deltaX
      | GLint
bx forall a. Eq a => a -> a -> Bool
== -GLint
1  = GLdouble
0
      | Bool
otherwise = forall a b. (Integral a, Num b) => a -> b
fromIntegral (GLint
x forall a. Num a => a -> a -> a
- GLint
bx)
    deltaY :: GLdouble
deltaY
      | GLint
by forall a. Eq a => a -> a -> Bool
== -GLint
1  = GLdouble
0
      | Bool
otherwise = forall a b. (Integral a, Num b) => a -> b
fromIntegral (GLint
y forall a. Num a => a -> a -> a
- GLint
by)
    deltaZ :: GLdouble
deltaZ
      | GLint
by forall a. Eq a => a -> a -> Bool
== -GLint
1  = GLdouble
0
      | Bool
otherwise = forall a b. (Integral a, Num b) => a -> b
fromIntegral (GLint
y forall a. Num a => a -> a -> a
- GLint
by)
    nextTheta' :: GLdouble
nextTheta'
      | GLdouble
deltaY forall a. Num a => a -> a -> a
+ GLdouble
theta0' forall a. Ord a => a -> a -> Bool
>  GLdouble
80 =  GLdouble
80
      | GLdouble
deltaY forall a. Num a => a -> a -> a
+ GLdouble
theta0' forall a. Ord a => a -> a -> Bool
< -GLdouble
80 = -GLdouble
80
      | Bool
otherwise              = GLdouble
deltaY forall a. Num a => a -> a -> a
+ GLdouble
theta0'
    nextX :: GLdouble
nextX = GLdouble
x0 forall a. Num a => a -> a -> a
+ GLdouble
0.003forall a. Num a => a -> a -> a
*GLdouble
rho0'forall a. Num a => a -> a -> a
*( -forall a. Floating a => a -> a
sin(GLdouble
phi0'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)forall a. Num a => a -> a -> a
*GLdouble
deltaX forall a. Num a => a -> a -> a
- forall a. Floating a => a -> a
cos(GLdouble
phi0'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)forall a. Num a => a -> a -> a
*GLdouble
deltaY)
    nextY :: GLdouble
nextY = GLdouble
y0 forall a. Num a => a -> a -> a
+ GLdouble
0.003forall a. Num a => a -> a -> a
*GLdouble
rho0'forall a. Num a => a -> a -> a
*(  forall a. Floating a => a -> a
cos(GLdouble
phi0'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)forall a. Num a => a -> a -> a
*GLdouble
deltaX forall a. Num a => a -> a -> a
- forall a. Floating a => a -> a
sin(GLdouble
phi0'forall a. Num a => a -> a -> a
*forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/GLdouble
180)forall a. Num a => a -> a -> a
*GLdouble
deltaY)
    nextZ :: GLdouble
nextZ = GLdouble
z0 forall a. Num a => a -> a -> a
- GLdouble
0.001forall a. Num a => a -> a -> a
*GLdouble
rho0'forall a. Num a => a -> a -> a
*GLdouble
deltaZ

    (GLdouble
nextPhi, GLdouble
nextTheta) = if GLint
lb forall a. Eq a => a -> a -> Bool
== GLint
1
                           then (GLdouble
phi0' forall a. Num a => a -> a -> a
+ GLdouble
deltaX, GLdouble
nextTheta')
                           else (GLdouble
phi0', GLdouble
theta0')

    nextPos :: V3 GLdouble
nextPos
      | GLint
rb forall a. Eq a => a -> a -> Bool
== GLint
1 = forall a. a -> a -> a -> V3 a
V3 GLdouble
nextX GLdouble
nextY GLdouble
z0
      | GLint
mb forall a. Eq a => a -> a -> Bool
== GLint
1 = forall a. a -> a -> a -> V3 a
V3 GLdouble
x0 GLdouble
y0 GLdouble
nextZ
      | Bool
otherwise = forall a. a -> a -> a -> V3 a
V3 GLdouble
x0 GLdouble
y0 GLdouble
z0

    nextBallX :: GLint
nextBallX = GLint
x
    nextBallY :: GLint
nextBallY = GLint
y

cameraKeyboardMouse :: Camera -> Key -> KeyState -> Camera
cameraKeyboardMouse :: Camera -> Key -> KeyState -> Camera
cameraKeyboardMouse Camera
camera Key
key KeyState
keyState =
  Camera
camera {rho :: GLdouble
rho = GLdouble
newRho, leftButton :: GLint
leftButton = GLint
lb, rightButton :: GLint
rightButton = GLint
rb, middleButton :: GLint
middleButton = GLint
mb, ballX :: GLint
ballX = GLint
bx, ballY :: GLint
ballY = GLint
by}
  where
    (GLint
lb, Bool
reset0) = case (Key
key, KeyState
keyState) of (MouseButton MouseButton
LeftButton, KeyState
Down) -> (GLint
1, Bool
True)
                                           (MouseButton MouseButton
LeftButton, KeyState
Up) -> (GLint
0, Bool
False)
                                           (Key, KeyState)
_ -> (Camera -> GLint
leftButton Camera
camera, Bool
False)
    (GLint
rb, Bool
reset1) = case (Key
key, KeyState
keyState) of (MouseButton MouseButton
RightButton, KeyState
Down) -> (GLint
1, Bool
True)
                                           (MouseButton MouseButton
RightButton, KeyState
Up) -> (GLint
0, Bool
False)
                                           (Key, KeyState)
_ -> (Camera -> GLint
rightButton Camera
camera, Bool
False)
    (GLint
mb, Bool
reset2) = case (Key
key, KeyState
keyState) of (MouseButton MouseButton
MiddleButton, KeyState
Down) -> (GLint
1, Bool
True)
                                           (MouseButton MouseButton
MiddleButton, KeyState
Up) -> (GLint
0, Bool
False)
                                           (Key, KeyState)
_ -> (Camera -> GLint
middleButton Camera
camera, Bool
False)
  
    (GLint
bx,GLint
by) = if Bool
reset0 Bool -> Bool -> Bool
|| Bool
reset1 Bool -> Bool -> Bool
|| Bool
reset2 then (-GLint
1,-GLint
1) else (Camera -> GLint
ballX Camera
camera, Camera -> GLint
ballY Camera
camera)
  
    newRho :: GLdouble
newRho = case (Key
key, KeyState
keyState) of (MouseButton MouseButton
WheelUp, KeyState
Down)   -> GLdouble
0.9 forall a. Num a => a -> a -> a
* (Camera -> GLdouble
rho Camera
camera)
                                     (MouseButton MouseButton
WheelDown, KeyState
Down) -> GLdouble
1.1 forall a. Num a => a -> a -> a
* (Camera -> GLdouble
rho Camera
camera)
                                     (Char Char
'e', KeyState
Down)   -> GLdouble
0.9 forall a. Num a => a -> a -> a
* (Camera -> GLdouble
rho Camera
camera)
                                     (Char Char
'q', KeyState
Down) -> GLdouble
1.1 forall a. Num a => a -> a -> a
* (Camera -> GLdouble
rho Camera
camera)
                                     (Key, KeyState)
_ -> Camera -> GLdouble
rho Camera
camera