mischief-math-0.1.0.0: src/Mischief/Math/Transform.hs
{-# 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 {transform :: Transform}
deriving anyclass (Component, Default)
deriving stock (Generic, Show)
data Transform = Transform {translation :: V3 Float, rotation :: Quat, scale :: V3 Float} deriving (Generic, Show, Eq)
instance Default Transform where
def = Transform {translation = V3 0 0 0, rotation = def, scale = V3 1 1 1}
instance Component Transform where
onAdd =
[ hook $ \HookContext {entity} -> do
Just transform <- single [q|entity. Transform|]
insert (GlobalTransform transform) entity
]
composeTransforms :: Transform -> Transform -> Transform
composeTransforms t1 t2 =
let Quat quat1 = t1.rotation
in Transform
{ translation = t1.translation + (quat1 `Quaternion.rotate` (t1.scale * t2.translation)),
rotation = t1.rotation * t2.rotation,
scale = t1.scale * t2.scale
}
setRotation :: Quat -> Transform -> Transform
setRotation rotation Transform {translation, scale} =
Transform {translation, rotation, scale}
setRotationAxis :: Dir3 Float -> Float -> Transform -> Transform
setRotationAxis dir angle Transform {translation, scale} =
Transform {translation, rotation = Quat.fromAxisAngle dir angle, scale}
setTranslation :: V3 Float -> Transform -> Transform
setTranslation translation Transform {rotation, scale} =
Transform {translation, rotation, scale}
setScale :: V3 Float -> Transform -> Transform
setScale scale Transform {rotation, translation} =
Transform {translation, rotation, scale}
move :: V3 Float -> Transform -> Transform
move trans Transform {translation, rotation, scale} =
Transform {translation = translation + trans, rotation, scale}
scale :: V3 Float -> Transform -> Transform
scale sc Transform {translation, rotation, scale} =
Transform {translation, rotation, scale = scale * sc}
rotate :: Quat -> Transform -> Transform
rotate rot Transform {translation, rotation, scale} =
Transform {translation, rotation = rotation * rot, scale}
rotateAxis :: Dir3 Float -> Float -> Transform -> Transform
rotateAxis dir angle Transform {translation, rotation, scale} =
Transform {translation, rotation = Quat.rotateAxis dir angle rotation, scale}
rotateX :: Float -> Transform -> Transform
rotateX angle Transform {translation, rotation, scale} =
Transform {translation, rotation = Quat.rotateX angle rotation, scale}
rotateY :: Float -> Transform -> Transform
rotateY angle Transform {translation, rotation, scale} =
Transform {translation, rotation = Quat.rotateY angle rotation, scale}
rotateZ :: Float -> Transform -> Transform
rotateZ angle Transform {translation, rotation, scale} =
Transform {translation, rotation = Quat.rotateZ angle rotation, scale}