{-# OPTIONS_GHC -Wno-missing-methods #-}

module Mischief.Math.Transform where

import Data.Default (Default)
import GHC.Generics (Generic)
import Linear.Quaternion qualified as Quaternion
import Mischief.ECS (Tick, def)
import Mischief.ECS.Components (Component (onAdd))
import Mischief.ECS.Components.HooksDef
  ( HookContext (HookContext, entity),
  )
import Mischief.ECS.Exports (Default, Generic)
import Mischief.ECS.Hooks (hook)
import Mischief.ECS.World.Insert (insert)
import Mischief.ECS.World.Query (single)
import Mischief.ECS.World.Query.TH (q)
import Mischief.Math.Quat (Quat (Quat))
import Mischief.Math.Quat qualified as Quat
import Mischief.Math.Vec
import Mischief.Math.Vec.Orphans.Default ()

newtype GlobalTransform = GlobalTransform {GlobalTransform -> Transform
transform :: Transform}
  deriving anyclass (Typeable GlobalTransform
[Hook GlobalTransform]
[HookRel GlobalTransform]
Set DefaultComponentType
IsExclusive (IsExclusiveRel GlobalTransform)
(Typeable GlobalTransform,
 IsExclusive (IsExclusiveRel GlobalTransform)) =>
Set DefaultComponentType
-> [Hook GlobalTransform]
-> [Hook GlobalTransform]
-> [Hook GlobalTransform]
-> [HookRel GlobalTransform]
-> [HookRel GlobalTransform]
-> [HookRel GlobalTransform]
-> Component GlobalTransform
forall c.
(Typeable c, IsExclusive (IsExclusiveRel c)) =>
Set DefaultComponentType
-> [Hook c]
-> [Hook c]
-> [Hook c]
-> [HookRel c]
-> [HookRel c]
-> [HookRel c]
-> Component c
$crequired :: Set DefaultComponentType
required :: Set DefaultComponentType
$conAdd :: [Hook GlobalTransform]
onAdd :: [Hook GlobalTransform]
$conSet :: [Hook GlobalTransform]
onSet :: [Hook GlobalTransform]
$conRemove :: [Hook GlobalTransform]
onRemove :: [Hook GlobalTransform]
$conAddRel :: [HookRel GlobalTransform]
onAddRel :: [HookRel GlobalTransform]
$conSetRel :: [HookRel GlobalTransform]
onSetRel :: [HookRel GlobalTransform]
$conRemoveRel :: [HookRel GlobalTransform]
onRemoveRel :: [HookRel GlobalTransform]
Component, GlobalTransform
GlobalTransform -> Default GlobalTransform
forall a. a -> Default a
$cdef :: GlobalTransform
def :: GlobalTransform
Default)
  deriving stock ((forall x. GlobalTransform -> Rep GlobalTransform x)
-> (forall x. Rep GlobalTransform x -> GlobalTransform)
-> Generic GlobalTransform
forall x. Rep GlobalTransform x -> GlobalTransform
forall x. GlobalTransform -> Rep GlobalTransform x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. GlobalTransform -> Rep GlobalTransform x
from :: forall x. GlobalTransform -> Rep GlobalTransform x
$cto :: forall x. Rep GlobalTransform x -> GlobalTransform
to :: forall x. Rep GlobalTransform x -> GlobalTransform
Generic, Int -> GlobalTransform -> ShowS
[GlobalTransform] -> ShowS
GlobalTransform -> String
(Int -> GlobalTransform -> ShowS)
-> (GlobalTransform -> String)
-> ([GlobalTransform] -> ShowS)
-> Show GlobalTransform
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GlobalTransform -> ShowS
showsPrec :: Int -> GlobalTransform -> ShowS
$cshow :: GlobalTransform -> String
show :: GlobalTransform -> String
$cshowList :: [GlobalTransform] -> ShowS
showList :: [GlobalTransform] -> ShowS
Show)

data Transform = Transform {Transform -> V3 Float
translation :: V3 Float, Transform -> Quat
rotation :: Quat, Transform -> V3 Float
scale :: V3 Float} deriving ((forall x. Transform -> Rep Transform x)
-> (forall x. Rep Transform x -> Transform) -> Generic Transform
forall x. Rep Transform x -> Transform
forall x. Transform -> Rep Transform x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Transform -> Rep Transform x
from :: forall x. Transform -> Rep Transform x
$cto :: forall x. Rep Transform x -> Transform
to :: forall x. Rep Transform x -> Transform
Generic, Int -> Transform -> ShowS
[Transform] -> ShowS
Transform -> String
(Int -> Transform -> ShowS)
-> (Transform -> String)
-> ([Transform] -> ShowS)
-> Show Transform
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Transform -> ShowS
showsPrec :: Int -> Transform -> ShowS
$cshow :: Transform -> String
show :: Transform -> String
$cshowList :: [Transform] -> ShowS
showList :: [Transform] -> ShowS
Show, Transform -> Transform -> Bool
(Transform -> Transform -> Bool)
-> (Transform -> Transform -> Bool) -> Eq Transform
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Transform -> Transform -> Bool
== :: Transform -> Transform -> Bool
$c/= :: Transform -> Transform -> Bool
/= :: Transform -> Transform -> Bool
Eq)

instance Default Transform where
  def :: Transform
def = Transform {translation :: V3 Float
translation = Float -> Float -> Float -> V3 Float
forall a. a -> a -> a -> V3 a
V3 Float
0 Float
0 Float
0, rotation :: Quat
rotation = Quat
forall a. Default a => a
def, scale :: V3 Float
scale = Float -> Float -> Float -> V3 Float
forall a. a -> a -> a -> V3 a
V3 Float
1 Float
1 Float
1}

instance Component Transform where
  onAdd :: [Hook Transform]
onAdd =
    [ (HookContext -> System ()) -> Hook Transform
forall {k} (a :: k). (HookContext -> System ()) -> Hook a
hook ((HookContext -> System ()) -> Hook Transform)
-> (HookContext -> System ()) -> Hook Transform
forall a b. (a -> b) -> a -> b
$ \HookContext {Entity
entity :: HookContext -> Entity
entity :: Entity
entity} -> do
        Just transform <- Query System Transform -> System (Maybe Transform)
forall w (m :: * -> *) out.
MonadSystem w m =>
Query m out -> m (Maybe out)
single [q|entity. Transform|]
        insert (GlobalTransform transform) entity
    ]

composeTransforms :: Transform -> Transform -> Transform
composeTransforms :: Transform -> Transform -> Transform
composeTransforms Transform
t1 Transform
t2 =
  let Quat Quaternion Float
quat1 = Transform
t1.rotation
   in Transform
        { translation :: V3 Float
translation = Transform
t1.translation V3 Float -> V3 Float -> V3 Float
forall a. Num a => a -> a -> a
+ (Quaternion Float
quat1 Quaternion Float -> V3 Float -> V3 Float
forall a.
(Conjugate a, RealFloat a) =>
Quaternion a -> V3 a -> V3 a
`Quaternion.rotate` (Transform
t1.scale V3 Float -> V3 Float -> V3 Float
forall a. Num a => a -> a -> a
* Transform
t2.translation)),
          rotation :: Quat
rotation = Transform
t1.rotation Quat -> Quat -> Quat
forall a. Num a => a -> a -> a
* Transform
t2.rotation,
          scale :: V3 Float
scale = Transform
t1.scale V3 Float -> V3 Float -> V3 Float
forall a. Num a => a -> a -> a
* Transform
t2.scale
        }

setRotation :: Quat -> Transform -> Transform
setRotation :: Quat -> Transform -> Transform
setRotation Quat
rotation Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, Quat
rotation :: Quat
rotation :: Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

setRotationAxis :: Dir3 Float -> Float -> Transform -> Transform
setRotationAxis :: Dir3 Float -> Float -> Transform -> Transform
setRotationAxis Dir3 Float
dir Float
angle Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, rotation :: Quat
rotation = Dir3 Float -> Float -> Quat
Quat.fromAxisAngle Dir3 Float
dir Float
angle, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

setTranslation :: V3 Float -> Transform -> Transform
setTranslation :: V3 Float -> Transform -> Transform
setTranslation V3 Float
translation Transform {Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, Quat
rotation :: Quat
rotation :: Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

setScale :: V3 Float -> Transform -> Transform
setScale :: V3 Float -> Transform -> Transform
setScale V3 Float
scale Transform {Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, Quat
rotation :: Quat
rotation :: Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

move :: V3 Float -> Transform -> Transform
move :: V3 Float -> Transform -> Transform
move V3 Float
trans Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {translation :: V3 Float
translation = V3 Float
translation V3 Float -> V3 Float -> V3 Float
forall a. Num a => a -> a -> a
+ V3 Float
trans, Quat
rotation :: Quat
rotation :: Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

scale :: V3 Float -> Transform -> Transform
scale :: V3 Float -> Transform -> Transform
scale V3 Float
sc Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, Quat
rotation :: Quat
rotation :: Quat
rotation, scale :: V3 Float
scale = V3 Float
scale V3 Float -> V3 Float -> V3 Float
forall a. Num a => a -> a -> a
* V3 Float
sc}

rotate :: Quat -> Transform -> Transform
rotate :: Quat -> Transform -> Transform
rotate Quat
rot Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, rotation :: Quat
rotation = Quat
rotation Quat -> Quat -> Quat
forall a. Num a => a -> a -> a
* Quat
rot, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

rotateAxis :: Dir3 Float -> Float -> Transform -> Transform
rotateAxis :: Dir3 Float -> Float -> Transform -> Transform
rotateAxis Dir3 Float
dir Float
angle Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, rotation :: Quat
rotation = Dir3 Float -> Float -> Quat -> Quat
Quat.rotateAxis Dir3 Float
dir Float
angle Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

rotateX :: Float -> Transform -> Transform
rotateX :: Float -> Transform -> Transform
rotateX Float
angle Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, rotation :: Quat
rotation = Float -> Quat -> Quat
Quat.rotateX Float
angle Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

rotateY :: Float -> Transform -> Transform
rotateY :: Float -> Transform -> Transform
rotateY Float
angle Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, rotation :: Quat
rotation = Float -> Quat -> Quat
Quat.rotateY Float
angle Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}

rotateZ :: Float -> Transform -> Transform
rotateZ :: Float -> Transform -> Transform
rotateZ Float
angle Transform {V3 Float
translation :: Transform -> V3 Float
translation :: V3 Float
translation, Quat
rotation :: Transform -> Quat
rotation :: Quat
rotation, V3 Float
scale :: Transform -> V3 Float
scale :: V3 Float
scale} =
  Transform {V3 Float
translation :: V3 Float
translation :: V3 Float
translation, rotation :: Quat
rotation = Float -> Quat -> Quat
Quat.rotateZ Float
angle Quat
rotation, V3 Float
scale :: V3 Float
scale :: V3 Float
scale}