```{-|
Module      : Game.GoreAndAsh.Math
Description : Common mathematic utilities in games
Copyright   : (c) Anton Gushcha, 2015-2016
Oganyan Levon, 2016
Maintainer  : ncrashed@gmail.com
Stability   : experimental
Portability : POSIX

Defines common math transformations for world, camera, vieport spaces.
-}
module Game.GoreAndAsh.Math(
-- * 3D matrix transformations
scale
, rotationZ
, translate
-- * 2D matrix transformations
, scale2D
, rotation2D
, translate2D
, toHom2D
, fromHom2D
, applyTransform2D
, viewportTransform2D
) where

import Linear

-- | Scale matrix for 3D transformation
scale :: Num a => V3 a -> M44 a
scale (V3 x y z) = V4
(V4 x 0 0 0)
(V4 0 y 0 0)
(V4 0 0 z 0)
(V4 0 0 0 1)

-- | Rotation around Z axis for 3D transformation
rotationZ :: Floating a => a -> M44 a
rotationZ a = V4
(V4 (cos a) (- sin a) 0 0)
(V4 (sin a) (  cos a) 0 0)
(V4 0 0 1 0)
(V4 0 0 0 1)

-- | Translation matrix for 3D transformation
translate :: Num a => V3 a -> M44 a
translate (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)

-- | Scale matrix for 2D transformation
scale2D :: Num a => V2 a -> M33 a
scale2D (V2 x y) = V3
(V3 x 0 0)
(V3 0 y 0)
(V3 0 0 1)

-- | Rotation matrix for 2D transformation
rotation2D :: Floating a => a -> M33 a
rotation2D a = V3
(V3 (cos a) (- sin a) 0)
(V3 (sin a) (  cos a) 0)
(V3 0 0 1)

-- | Translation matrix for 2D transformation
translate2D :: Num a => V2 a -> M33 a
translate2D (V2 x y) = V3
(V3 1 0 x)
(V3 0 1 y)
(V3 0 0 1)

-- | Transform to homogenius coordinates
toHom2D :: Num a => V2 a -> V3 a
toHom2D (V2 x y) = V3 x y 1

-- | Transform from homogenius coordinates
fromHom2D :: Floating a => V3 a -> V2 a
fromHom2D (V3 x y w) = V2 (x/w) (y/w)

-- | Applies transformation matrix to vector
applyTransform2D :: Floating a => M33 a -> V2 a -> V2 a
applyTransform2D mt v = fromHom2D \$ mt !* toHom2D v

-- | Viewport transformation matrix
viewportTransform2D :: Floating a
=> V2 a -- ^ Viewport left top corner
-> V2 a -- ^ Viewport right bottom corner
-> M33 a
viewportTransform2D (V2 l t) (V2 r b) = V3
(V3 ((r-l)/2) 0          ((r+l)/2))
(V3 0         (-(t-b)/2) ((t+b)/2))
(V3 0         0          1)
!*! scale2D (V2 1 a)
where
a = (r-l)/(t-b)
```