summaryrefslogtreecommitdiff
path: root/Matrix.hs
blob: 2e27d08e0adf2e0aad999c7c3ba68ebd16d69426 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{-# LANGUAGE BangPatterns, FlexibleContexts #-}
module Matrix where

import Numeric.LinearAlgebra
import Foreign.Storable
import Data.Vector.Generic as V (snoc,init)
import Prelude hiding ((<>))

-- | 3×3 rotation matrix about the x axis.
rotMatrixX :: (Storable a, Floating a) => a -> Matrix a
rotMatrixX a = (3><3)
    [ 1 , 0 , 0
    , 0 , c , -s
    , 0 , s , c ] where (c,s) = (cos a, sin a)


-- | 3×3 rotation matrix about the y axis.
rotMatrixY :: (Storable a, Floating a) => a -> Matrix a
rotMatrixY a = (3><3)
    [  c , 0 , s
    ,  0 , 1 , 0
    , -s , 0 , c ] where (c,s) = (cos a, sin a)

-- | 3×3 rotation matrix about the z axis.
rotMatrixZ :: (Storable a, Floating a) => a -> Matrix a
rotMatrixZ a = (3><3)
    [ c , -s , 0
    , s ,  c , 0
    , 0 ,  0 , 1 ] where (c,s) = (cos a, sin a)


-- | Camera transformation matrix (4×4).
lookat :: (Numeric t, Num (Vector t), Fractional t, Normed (Vector t)) =>
    Vector t    -- ^ Camera position 3-vector.
    -> Vector t -- ^ Target position 3-vector.
    -> Vector t -- ^ Upward direction 3-vector.
    -> Matrix t
lookat pos target up = fromRows
    [ snoc rightward         (- dot rightward pos)
    , snoc upward            (- dot upward    pos)
    , snoc backward          (- dot backward  pos)
    , snoc (fromList[0,0,0]) 1
    ]
  where
    backward  = normalize $ pos - target
    rightward = normalize $ up `cross` backward
    upward    = backward `cross` rightward

    -- Rebind 'normalize' in order to support Float which has no Field
    -- instance.
    normalize :: (Linear t c, Fractional t, Normed (c t)) => c t -> c t
    normalize v = scale (1 / realToFrac (norm_2 v)) v

{-# SPECIALIZE lookat :: Vector R -> Vector R -> Vector R -> Matrix R #-}


-- | Perspective transformation 4×4 matrix.
perspective :: (Storable a, Floating a) =>
                a    -- ^ Near plane clipping distance (always positive).
                -> a -- ^ Far plane clipping distance (always positive).
                -> a -- ^ Field of view of the y axis, in radians.
                -> a -- ^ Aspect ratio, i.e. screen's width\/height.
                -> Matrix a
perspective n f fovy aspect = (4><4)
    [ (2*n/(r-l)) , 0           , (-(r+l)/(r-l)) , 0
    , 0           , (2*n/(t-b)) , ((t+b)/(t-b))  , 0
    , 0           , 0           , (-(f+n)/(f-n)) , (-2*f*n/(f-n))
    , 0           , 0           , (-1)           , 0              ]
  where
    t = n*tan(fovy/2)
    b = -t
    r = aspect*t
    l = -r