packages feed

geomancy-0.2.2.3: src/Geomancy/Vulkan/Projection.hs

module Geomancy.Vulkan.Projection
  ( perspective
  , infinitePerspective
  , orthoOffCenter
  ) where

import Geomancy.Mat4 (colMajor)
import Geomancy.Transform (Transform(..))

perspective
  :: Integral side
  => Float
  -> Float -> Float
  -> side -> side
  -> Transform
perspective fovRads near far width height = colMajor
  x 0   0   0
  0 y   0   0
  0 0   z w23
  0 0 w32   1

  where
    x = cotFoV * aspectX
    y = -cotFoV
    z = far / (near - far)
    w23 = near * far / (near - far)
    w32 = -1

    cotFoV = recip . tan $ 0.5 * fovRads

    aspectX = fromIntegral height / fromIntegral width

infinitePerspective
  :: Integral side
  => Float
  -> side
  -> side
  -> Transform
infinitePerspective fovRads width height = colMajor
  x   0   0  0
  0 (-y)  0  0
  0   0 (-1) w
  0   0 (-1) 0
  where
    (x, y) =
      if width > height then
        ( cotFoV / camAspect
        , cotFoV
        )
      else
        ( cotFoV
        , cotFoV * camAspect
        )
    camAspect = fromIntegral width / fromIntegral height
    cotFoV = recip . tan $ 0.5 * fovRads

    w = -2 * near
    near = 1/128 -- 2048

orthoOffCenter :: Integral side => Float -> Float -> side -> side -> Transform
orthoOffCenter near far width height = colMajor
  x 0 0 0
  0 y 0 0
  0 0 z w
  0 0 0 1

  where
    x = 2 / fromIntegral width
    y = 2 / fromIntegral height
    z = 1 / (far - near)

    w = near * (near - far)