packages feed

scenegraph-0.2.0.0: src/Graphics/SceneGraph/Matrix.hs

{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TypeSynonymInstances   #-}
module Graphics.SceneGraph.Matrix
  ( translateM
  , translatePostM
  , scaleM
  , rotateM
  , rotatePostM
  ) where

-- Warning: Because this matrix is going to get passed directly to GL we convert to GL space
-- here.

import           Control.Lens ((^.))
import           Linear       (M44, R1 (..), R2 (..), R3 (..), V3 (..), V4 (..),
                               (!*!))


asMatrix :: V3 Float -> M44 Float
asMatrix (V3 x y z) = V4
  (V4 1 0 0 x)
  (V4 0 1 0 y)
  (V4 0 0 1 z)
  (V4 0 0 0 1)

translateM :: V3 Float -> M44 Float -> M44 Float
translateM v m = asMatrix v !*! m

translatePostM :: V3 Float -> M44 Float -> M44 Float
translatePostM v m = m !*! asMatrix v

scaleM :: V3 Float -> M44 Float -> M44 Float
scaleM v m = m !*! V4
  (V4 (v^._x) 0 0 0)
  (V4 0 (v^._y) 0 0)
  (V4 0 0 (v^._z) 0)
  (V4 0 0 0 1)

-- | Build rotational transform matrix for rotate of ''theta'' around a vector.
rotateM' :: Float -> V3 Float -> M44 Float
rotateM' theta (V3 x y z) = V4
  (V4 (t*x*x + c) (t*x*y-s*z) (t*x*z + s*y) 0)
  (V4 (t*x*y+s*z) (t*y*y + c) (t*y*z - s*x)  0)
  (V4 (t*x*z-s*y) (t*y*z + s*x) (t*z*z+c) 0)
  (V4 0 0 0 1)
  where
    t = 1 - cos theta
    c = cos theta
    s = sin theta

rotateM :: Float -> V3 Float -> M44 Float -> M44 Float
rotateM theta v m = rotateM' theta v !*! m

rotatePostM :: Float -> V3 Float -> M44 Float -> M44 Float
rotatePostM theta v m = m !*! rotateM' theta v