module Engine.Camera
  ( ProjectionKind(..)
  , Projection(..)
  , ProjectionParams
  , ProjectionInput(..)
  , ProjectionProcess
  , spawnPerspective
  , mkTransformPerspective

  , spawnOrthoPixelsCentered
  , mkTransformOrthoPixelsCentered

  , spawnProjectionWith

  , spawnProjection
  , pattern PROJECTION_NEAR
  , pattern PROJECTION_FAR

  , View(..)
  , ViewProcess
  , ViewOrbitalInput(..)
  , initialOrbitalInput
  , mkViewOrbital
  , mkViewOrbital_
  ) where

import RIO

import Geomancy (Transform(..), Vec3, vec3)
import Geomancy.Transform qualified as Transform
import Geomancy.Quaternion qualified as Quaternion
import Geomancy.Vec3 qualified as Vec3
import Geomancy.Vulkan.Projection qualified as Projection
import Geomancy.Vulkan.View qualified as View
import Vulkan.Core10 qualified as Vk
import Vulkan.NamedType ((:::))

import Engine.Types qualified as Engine
import Engine.Worker qualified as Worker

-- * Projection

data ProjectionKind
  = Perspective
  | Orthographic
  deriving (ProjectionKind -> ProjectionKind -> Bool
(ProjectionKind -> ProjectionKind -> Bool)
-> (ProjectionKind -> ProjectionKind -> Bool) -> Eq ProjectionKind
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ProjectionKind -> ProjectionKind -> Bool
$c/= :: ProjectionKind -> ProjectionKind -> Bool
== :: ProjectionKind -> ProjectionKind -> Bool
$c== :: ProjectionKind -> ProjectionKind -> Bool
Eq, Eq ProjectionKind
Eq ProjectionKind
-> (ProjectionKind -> ProjectionKind -> Ordering)
-> (ProjectionKind -> ProjectionKind -> Bool)
-> (ProjectionKind -> ProjectionKind -> Bool)
-> (ProjectionKind -> ProjectionKind -> Bool)
-> (ProjectionKind -> ProjectionKind -> Bool)
-> (ProjectionKind -> ProjectionKind -> ProjectionKind)
-> (ProjectionKind -> ProjectionKind -> ProjectionKind)
-> Ord ProjectionKind
ProjectionKind -> ProjectionKind -> Bool
ProjectionKind -> ProjectionKind -> Ordering
ProjectionKind -> ProjectionKind -> ProjectionKind
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: ProjectionKind -> ProjectionKind -> ProjectionKind
$cmin :: ProjectionKind -> ProjectionKind -> ProjectionKind
max :: ProjectionKind -> ProjectionKind -> ProjectionKind
$cmax :: ProjectionKind -> ProjectionKind -> ProjectionKind
>= :: ProjectionKind -> ProjectionKind -> Bool
$c>= :: ProjectionKind -> ProjectionKind -> Bool
> :: ProjectionKind -> ProjectionKind -> Bool
$c> :: ProjectionKind -> ProjectionKind -> Bool
<= :: ProjectionKind -> ProjectionKind -> Bool
$c<= :: ProjectionKind -> ProjectionKind -> Bool
< :: ProjectionKind -> ProjectionKind -> Bool
$c< :: ProjectionKind -> ProjectionKind -> Bool
compare :: ProjectionKind -> ProjectionKind -> Ordering
$ccompare :: ProjectionKind -> ProjectionKind -> Ordering
Ord, Int -> ProjectionKind -> ShowS
[ProjectionKind] -> ShowS
ProjectionKind -> String
(Int -> ProjectionKind -> ShowS)
-> (ProjectionKind -> String)
-> ([ProjectionKind] -> ShowS)
-> Show ProjectionKind
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ProjectionKind] -> ShowS
$cshowList :: [ProjectionKind] -> ShowS
show :: ProjectionKind -> String
$cshow :: ProjectionKind -> String
showsPrec :: Int -> ProjectionKind -> ShowS
$cshowsPrec :: Int -> ProjectionKind -> ShowS
Show, Int -> ProjectionKind
ProjectionKind -> Int
ProjectionKind -> [ProjectionKind]
ProjectionKind -> ProjectionKind
ProjectionKind -> ProjectionKind -> [ProjectionKind]
ProjectionKind
-> ProjectionKind -> ProjectionKind -> [ProjectionKind]
(ProjectionKind -> ProjectionKind)
-> (ProjectionKind -> ProjectionKind)
-> (Int -> ProjectionKind)
-> (ProjectionKind -> Int)
-> (ProjectionKind -> [ProjectionKind])
-> (ProjectionKind -> ProjectionKind -> [ProjectionKind])
-> (ProjectionKind -> ProjectionKind -> [ProjectionKind])
-> (ProjectionKind
    -> ProjectionKind -> ProjectionKind -> [ProjectionKind])
-> Enum ProjectionKind
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: ProjectionKind
-> ProjectionKind -> ProjectionKind -> [ProjectionKind]
$cenumFromThenTo :: ProjectionKind
-> ProjectionKind -> ProjectionKind -> [ProjectionKind]
enumFromTo :: ProjectionKind -> ProjectionKind -> [ProjectionKind]
$cenumFromTo :: ProjectionKind -> ProjectionKind -> [ProjectionKind]
enumFromThen :: ProjectionKind -> ProjectionKind -> [ProjectionKind]
$cenumFromThen :: ProjectionKind -> ProjectionKind -> [ProjectionKind]
enumFrom :: ProjectionKind -> [ProjectionKind]
$cenumFrom :: ProjectionKind -> [ProjectionKind]
fromEnum :: ProjectionKind -> Int
$cfromEnum :: ProjectionKind -> Int
toEnum :: Int -> ProjectionKind
$ctoEnum :: Int -> ProjectionKind
pred :: ProjectionKind -> ProjectionKind
$cpred :: ProjectionKind -> ProjectionKind
succ :: ProjectionKind -> ProjectionKind
$csucc :: ProjectionKind -> ProjectionKind
Enum, ProjectionKind
ProjectionKind -> ProjectionKind -> Bounded ProjectionKind
forall a. a -> a -> Bounded a
maxBound :: ProjectionKind
$cmaxBound :: ProjectionKind
minBound :: ProjectionKind
$cminBound :: ProjectionKind
Bounded, (forall x. ProjectionKind -> Rep ProjectionKind x)
-> (forall x. Rep ProjectionKind x -> ProjectionKind)
-> Generic ProjectionKind
forall x. Rep ProjectionKind x -> ProjectionKind
forall x. ProjectionKind -> Rep ProjectionKind x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ProjectionKind x -> ProjectionKind
$cfrom :: forall x. ProjectionKind -> Rep ProjectionKind x
Generic)

data Projection (pk :: ProjectionKind) = Projection
  { forall (pk :: ProjectionKind). Projection pk -> Transform
projectionTransform :: Transform
  , forall (pk :: ProjectionKind). Projection pk -> Transform
projectionInverse   :: ~Transform
  }
  deriving (Int -> Projection pk -> ShowS
[Projection pk] -> ShowS
Projection pk -> String
(Int -> Projection pk -> ShowS)
-> (Projection pk -> String)
-> ([Projection pk] -> ShowS)
-> Show (Projection pk)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (pk :: ProjectionKind). Int -> Projection pk -> ShowS
forall (pk :: ProjectionKind). [Projection pk] -> ShowS
forall (pk :: ProjectionKind). Projection pk -> String
showList :: [Projection pk] -> ShowS
$cshowList :: forall (pk :: ProjectionKind). [Projection pk] -> ShowS
show :: Projection pk -> String
$cshow :: forall (pk :: ProjectionKind). Projection pk -> String
showsPrec :: Int -> Projection pk -> ShowS
$cshowsPrec :: forall (pk :: ProjectionKind). Int -> Projection pk -> ShowS
Show, (forall x. Projection pk -> Rep (Projection pk) x)
-> (forall x. Rep (Projection pk) x -> Projection pk)
-> Generic (Projection pk)
forall x. Rep (Projection pk) x -> Projection pk
forall x. Projection pk -> Rep (Projection pk) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (pk :: ProjectionKind) x.
Rep (Projection pk) x -> Projection pk
forall (pk :: ProjectionKind) x.
Projection pk -> Rep (Projection pk) x
$cto :: forall (pk :: ProjectionKind) x.
Rep (Projection pk) x -> Projection pk
$cfrom :: forall (pk :: ProjectionKind) x.
Projection pk -> Rep (Projection pk) x
Generic)

type ProjectionProcess pk = Worker.Cell (ProjectionInput pk) (Projection pk)

data ProjectionInput (pk :: ProjectionKind) = ProjectionInput
  { forall (pk :: ProjectionKind).
ProjectionInput pk -> ProjectionParams pk
projectionParams :: ProjectionParams pk
  , forall (pk :: ProjectionKind). ProjectionInput pk -> Float
projectionNear   :: Float
  , forall (pk :: ProjectionKind). ProjectionInput pk -> Float
projectionFar    :: Float
  }

-- XXX: undecidable
-- deriving instance (Show (ProjectionParams pk)) => Show (ProjectionInput pk)

type family ProjectionParams (pk :: ProjectionKind) where
  ProjectionParams 'Perspective = "fov-v" ::: Float
  ProjectionParams 'Orthographic = ()

spawnProjection
  :: (Vk.Extent2D -> ProjectionInput pk -> Transform)
  -> ProjectionParams pk
  -> Engine.StageRIO env (ProjectionProcess pk)
spawnProjection :: forall (pk :: ProjectionKind) env.
(Extent2D -> ProjectionInput pk -> Transform)
-> ProjectionParams pk -> StageRIO env (ProjectionProcess pk)
spawnProjection Extent2D -> ProjectionInput pk -> Transform
mkTransform ProjectionParams pk
params =
  (Extent2D -> ProjectionInput pk -> Transform)
-> ProjectionInput pk -> StageRIO env (ProjectionProcess pk)
forall (pk :: ProjectionKind) env.
(Extent2D -> ProjectionInput pk -> Transform)
-> ProjectionInput pk -> StageRIO env (ProjectionProcess pk)
spawnProjectionWith Extent2D -> ProjectionInput pk -> Transform
mkTransform ProjectionInput :: forall (pk :: ProjectionKind).
ProjectionParams pk -> Float -> Float -> ProjectionInput pk
ProjectionInput
    { $sel:projectionNear:ProjectionInput :: Float
projectionNear    = Float
forall a. (Eq a, Num a, Fractional a) => a
PROJECTION_NEAR
    , $sel:projectionFar:ProjectionInput :: Float
projectionFar     = Float
forall a. (Eq a, Num a) => a
PROJECTION_FAR
    , $sel:projectionParams:ProjectionInput :: ProjectionParams pk
projectionParams  = ProjectionParams pk
params
    }

pattern PROJECTION_NEAR :: (Eq a, Num a, Fractional a) => a
pattern $bPROJECTION_NEAR :: forall a. (Eq a, Num a, Fractional a) => a
$mPROJECTION_NEAR :: forall {r} {a}.
(Eq a, Num a, Fractional a) =>
a -> (Void# -> r) -> (Void# -> r) -> r
PROJECTION_NEAR = 0x0.02 -- i.e. 1/2048

pattern PROJECTION_FAR :: (Eq a, Num a) => a
pattern $bPROJECTION_FAR :: forall a. (Eq a, Num a) => a
$mPROJECTION_FAR :: forall {r} {a}.
(Eq a, Num a) =>
a -> (Void# -> r) -> (Void# -> r) -> r
PROJECTION_FAR = 16384

spawnProjectionWith
  :: (Vk.Extent2D -> ProjectionInput pk -> Transform)
  -> ProjectionInput pk
  -> Engine.StageRIO env (ProjectionProcess pk)
spawnProjectionWith :: forall (pk :: ProjectionKind) env.
(Extent2D -> ProjectionInput pk -> Transform)
-> ProjectionInput pk -> StageRIO env (ProjectionProcess pk)
spawnProjectionWith Extent2D -> ProjectionInput pk -> Transform
mkTransform ProjectionInput pk
projectionInput = do
  Var Extent2D
screen <- StageRIO env (Var Extent2D)
forall env. StageRIO env (Var Extent2D)
Engine.askScreenVar
  Var (ProjectionInput pk)
input <- ProjectionInput pk
-> RIO (App GlobalHandles env) (Var (ProjectionInput pk))
forall (m :: * -> *) a. MonadUnliftIO m => a -> m (Var a)
Worker.newVar ProjectionInput pk
projectionInput
  (Merge (Projection pk) -> ProjectionProcess pk)
-> RIO (App GlobalHandles env) (Merge (Projection pk))
-> StageRIO env (ProjectionProcess pk)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Var (ProjectionInput pk)
input,) (RIO (App GlobalHandles env) (Merge (Projection pk))
 -> StageRIO env (ProjectionProcess pk))
-> RIO (App GlobalHandles env) (Merge (Projection pk))
-> StageRIO env (ProjectionProcess pk)
forall a b. (a -> b) -> a -> b
$
    (GetOutput (Var Extent2D)
 -> GetOutput (Var (ProjectionInput pk)) -> Projection pk)
-> Var Extent2D
-> Var (ProjectionInput pk)
-> RIO (App GlobalHandles env) (Merge (Projection pk))
forall (m :: * -> *) i1 i2 o.
(MonadUnliftIO m, HasOutput i1, HasOutput i2) =>
(GetOutput i1 -> GetOutput i2 -> o) -> i1 -> i2 -> m (Merge o)
Worker.spawnMerge2
      (\GetOutput (Var Extent2D)
s GetOutput (Var (ProjectionInput pk))
i ->
          let
            transform :: Transform
transform = Extent2D -> ProjectionInput pk -> Transform
mkTransform Extent2D
GetOutput (Var Extent2D)
s GetOutput (Var (ProjectionInput pk))
ProjectionInput pk
i
          in
            Projection :: forall (pk :: ProjectionKind).
Transform -> Transform -> Projection pk
Projection
              { $sel:projectionTransform:Projection :: Transform
projectionTransform = Transform
transform
              , $sel:projectionInverse:Projection :: Transform
projectionInverse   = Transform -> Transform
forall a. (Coercible Mat4 a, Coercible Mat4 a) => a -> a
Transform.inverse Transform
transform -- XXX: better provide an inverse directly
              }
      )
      Var Extent2D
screen
      Var (ProjectionInput pk)
input

spawnPerspective :: Engine.StageRIO env (ProjectionProcess 'Perspective)
spawnPerspective :: forall env. StageRIO env (ProjectionProcess 'Perspective)
spawnPerspective = (Extent2D -> ProjectionInput 'Perspective -> Transform)
-> ProjectionParams 'Perspective
-> StageRIO env (ProjectionProcess 'Perspective)
forall (pk :: ProjectionKind) env.
(Extent2D -> ProjectionInput pk -> Transform)
-> ProjectionParams pk -> StageRIO env (ProjectionProcess pk)
spawnProjection Extent2D -> ProjectionInput 'Perspective -> Transform
mkTransformPerspective (Float
τ Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
4)

mkTransformPerspective :: Vk.Extent2D -> ProjectionInput 'Perspective -> Transform
mkTransformPerspective :: Extent2D -> ProjectionInput 'Perspective -> Transform
mkTransformPerspective Vk.Extent2D{Word32
$sel:width:Extent2D :: Extent2D -> Word32
width :: Word32
width, Word32
$sel:height:Extent2D :: Extent2D -> Word32
height :: Word32
height} ProjectionInput{Float
ProjectionParams 'Perspective
projectionFar :: Float
projectionNear :: Float
projectionParams :: ProjectionParams 'Perspective
$sel:projectionFar:ProjectionInput :: forall (pk :: ProjectionKind). ProjectionInput pk -> Float
$sel:projectionNear:ProjectionInput :: forall (pk :: ProjectionKind). ProjectionInput pk -> Float
$sel:projectionParams:ProjectionInput :: forall (pk :: ProjectionKind).
ProjectionInput pk -> ProjectionParams pk
..} =
  Float -> Float -> Float -> Word32 -> Word32 -> Transform
forall side.
Integral side =>
Float -> Float -> Float -> side -> side -> Transform
Projection.perspective
    Float
ProjectionParams 'Perspective
projectionParams
    Float
projectionNear
    Float
projectionFar
    Word32
width
    Word32
height

spawnOrthoPixelsCentered :: Engine.StageRIO env (ProjectionProcess 'Orthographic)
spawnOrthoPixelsCentered :: forall env. StageRIO env (ProjectionProcess 'Orthographic)
spawnOrthoPixelsCentered = (Extent2D -> ProjectionInput 'Orthographic -> Transform)
-> ProjectionInput 'Orthographic
-> StageRIO env (ProjectionProcess 'Orthographic)
forall (pk :: ProjectionKind) env.
(Extent2D -> ProjectionInput pk -> Transform)
-> ProjectionInput pk -> StageRIO env (ProjectionProcess pk)
spawnProjectionWith Extent2D -> ProjectionInput 'Orthographic -> Transform
mkTransformOrthoPixelsCentered ProjectionInput :: forall (pk :: ProjectionKind).
ProjectionParams pk -> Float -> Float -> ProjectionInput pk
ProjectionInput
  { $sel:projectionNear:ProjectionInput :: Float
projectionNear   = Float
0
  , $sel:projectionFar:ProjectionInput :: Float
projectionFar    = Float
1
  , $sel:projectionParams:ProjectionInput :: ProjectionParams 'Orthographic
projectionParams = ()
  }

mkTransformOrthoPixelsCentered :: Vk.Extent2D -> ProjectionInput 'Orthographic -> Transform
mkTransformOrthoPixelsCentered :: Extent2D -> ProjectionInput 'Orthographic -> Transform
mkTransformOrthoPixelsCentered Vk.Extent2D{Word32
width :: Word32
$sel:width:Extent2D :: Extent2D -> Word32
width, Word32
height :: Word32
$sel:height:Extent2D :: Extent2D -> Word32
height} ProjectionInput{Float
ProjectionParams 'Orthographic
projectionFar :: Float
projectionNear :: Float
projectionParams :: ProjectionParams 'Orthographic
$sel:projectionFar:ProjectionInput :: forall (pk :: ProjectionKind). ProjectionInput pk -> Float
$sel:projectionNear:ProjectionInput :: forall (pk :: ProjectionKind). ProjectionInput pk -> Float
$sel:projectionParams:ProjectionInput :: forall (pk :: ProjectionKind).
ProjectionInput pk -> ProjectionParams pk
..} =
  Float -> Float -> Word32 -> Word32 -> Transform
forall side.
Integral side =>
Float -> Float -> side -> side -> Transform
Projection.orthoOffCenter Float
projectionNear Float
projectionFar Word32
width Word32
height

-- * View

data View = View
  { View -> Transform
viewTransform    :: Transform
  , View -> Transform
viewTransformInv :: Transform
  , View -> Vec3
viewPosition     :: Vec3
  , View -> Vec3
viewDirection    :: Vec3
  }
  deriving (Int -> View -> ShowS
[View] -> ShowS
View -> String
(Int -> View -> ShowS)
-> (View -> String) -> ([View] -> ShowS) -> Show View
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [View] -> ShowS
$cshowList :: [View] -> ShowS
show :: View -> String
$cshow :: View -> String
showsPrec :: Int -> View -> ShowS
$cshowsPrec :: Int -> View -> ShowS
Show)

type ViewProcess = Worker.Cell ViewOrbitalInput View

-- | Camera orbiting its target
data ViewOrbitalInput = ViewOrbitalInput
  { ViewOrbitalInput -> Float
orbitAzimuth  :: Float
  , ViewOrbitalInput -> Float
orbitAscent   :: Float
  , ViewOrbitalInput -> Float
orbitDistance :: Float
  , ViewOrbitalInput -> Float
orbitScale    :: Float
  , ViewOrbitalInput -> Vec3
orbitTarget   :: Vec3
  , ViewOrbitalInput -> Vec3
orbitUp       :: Vec3
  , ViewOrbitalInput -> Vec3
orbitRight    :: Vec3
  }
  deriving (Int -> ViewOrbitalInput -> ShowS
[ViewOrbitalInput] -> ShowS
ViewOrbitalInput -> String
(Int -> ViewOrbitalInput -> ShowS)
-> (ViewOrbitalInput -> String)
-> ([ViewOrbitalInput] -> ShowS)
-> Show ViewOrbitalInput
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ViewOrbitalInput] -> ShowS
$cshowList :: [ViewOrbitalInput] -> ShowS
show :: ViewOrbitalInput -> String
$cshow :: ViewOrbitalInput -> String
showsPrec :: Int -> ViewOrbitalInput -> ShowS
$cshowsPrec :: Int -> ViewOrbitalInput -> ShowS
Show)

initialOrbitalInput :: ViewOrbitalInput
initialOrbitalInput :: ViewOrbitalInput
initialOrbitalInput = ViewOrbitalInput :: Float
-> Float
-> Float
-> Float
-> Vec3
-> Vec3
-> Vec3
-> ViewOrbitalInput
ViewOrbitalInput
  { $sel:orbitAzimuth:ViewOrbitalInput :: Float
orbitAzimuth  = Float
0 -- τ/8
  , $sel:orbitAscent:ViewOrbitalInput :: Float
orbitAscent   = Float
τFloat -> Float -> Float
forall a. Fractional a => a -> a -> a
/Float
7
  , $sel:orbitDistance:ViewOrbitalInput :: Float
orbitDistance = Float
8.0
  , $sel:orbitScale:ViewOrbitalInput :: Float
orbitScale    = Float
1
  , $sel:orbitTarget:ViewOrbitalInput :: Vec3
orbitTarget   = Vec3
0
  , $sel:orbitUp:ViewOrbitalInput :: Vec3
orbitUp       = Float -> Float -> Float -> Vec3
vec3 Float
0 (-Float
1) Float
0
  , $sel:orbitRight:ViewOrbitalInput :: Vec3
orbitRight    = Float -> Float -> Float -> Vec3
vec3 Float
1 Float
0 Float
0
  }

mkViewOrbital :: Vec3 -> ViewOrbitalInput -> View
mkViewOrbital :: Vec3 -> ViewOrbitalInput -> View
mkViewOrbital Vec3
cameraTarget ViewOrbitalInput{Float
Vec3
orbitRight :: Vec3
orbitUp :: Vec3
orbitTarget :: Vec3
orbitScale :: Float
orbitDistance :: Float
orbitAscent :: Float
orbitAzimuth :: Float
$sel:orbitRight:ViewOrbitalInput :: ViewOrbitalInput -> Vec3
$sel:orbitUp:ViewOrbitalInput :: ViewOrbitalInput -> Vec3
$sel:orbitTarget:ViewOrbitalInput :: ViewOrbitalInput -> Vec3
$sel:orbitScale:ViewOrbitalInput :: ViewOrbitalInput -> Float
$sel:orbitDistance:ViewOrbitalInput :: ViewOrbitalInput -> Float
$sel:orbitAscent:ViewOrbitalInput :: ViewOrbitalInput -> Float
$sel:orbitAzimuth:ViewOrbitalInput :: ViewOrbitalInput -> Float
..} = View :: Transform -> Transform -> Vec3 -> Vec3 -> View
View{Transform
Vec3
viewDirection :: Vec3
viewPosition :: Vec3
viewTransformInv :: Transform
viewTransform :: Transform
$sel:viewDirection:View :: Vec3
$sel:viewPosition:View :: Vec3
$sel:viewTransformInv:View :: Transform
$sel:viewTransform:View :: Transform
..}
  where
    viewTransform :: Transform
viewTransform = Vec3 -> Vec3 -> Vec3 -> Transform
View.lookAt Vec3
viewPosition Vec3
cameraTarget Vec3
orbitUp
    viewTransformInv :: Transform
viewTransformInv = Transform -> Transform
forall a. (Coercible Mat4 a, Coercible Mat4 a) => a -> a
Transform.inverse Transform
viewTransform

    viewPosition :: Vec3
viewPosition =
      Vec3
orbitTarget Vec3 -> Vec3 -> Vec3
forall a. Num a => a -> a -> a
+
      Quaternion -> Vec3 -> Vec3
Quaternion.rotate
        ( Vec3 -> Float -> Quaternion
Quaternion.axisAngle Vec3
orbitUp Float
orbitAzimuth Quaternion -> Quaternion -> Quaternion
forall a. Num a => a -> a -> a
*
          Vec3 -> Float -> Quaternion
Quaternion.axisAngle Vec3
orbitRight Float
orbitAscent
        )
        (Float -> Float -> Float -> Vec3
vec3 Float
0 Float
0 (Float -> Vec3) -> Float -> Vec3
forall a b. (a -> b) -> a -> b
$ Float
orbitDistance Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
orbitScale)

    viewDirection :: Vec3
viewDirection = Vec3 -> Vec3
Vec3.normalize (Vec3 -> Vec3) -> Vec3 -> Vec3
forall a b. (a -> b) -> a -> b
$ Vec3
cameraTarget Vec3 -> Vec3 -> Vec3
forall a. Num a => a -> a -> a
- Vec3
viewPosition

{-# INLINE mkViewOrbital_ #-}
mkViewOrbital_ :: ViewOrbitalInput -> View
mkViewOrbital_ :: ViewOrbitalInput -> View
mkViewOrbital_ ViewOrbitalInput
voi = Vec3 -> ViewOrbitalInput -> View
mkViewOrbital (ViewOrbitalInput -> Vec3
orbitTarget ViewOrbitalInput
voi) ViewOrbitalInput
voi

τ :: Float
τ :: Float
τ = Float
2 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
forall a. Floating a => a
pi