{-# LANGUAGE Arrows, MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving, TypeFamilies, ExistentialQuantification, Rank2Types #-} -- | Supports monadic and arrow operations for animated -- scenes. module RSAGL.Animation.Animation (AniM, TimePlusSceneAccumulator, frameTime, runAniM, rotationM, animateM, rotateM, AnimationObject, newAnimationObjectM, newAnimationObjectA, runAnimationObject) where import RSAGL.Scene.Scene import Control.Monad.State import RSAGL.Scene.CoordinateSystems import RSAGL.Math.Angle import RSAGL.Math.Vector import RSAGL.Math.Affine import RSAGL.FRP -- | A time-aware scene accumulator. newtype TimePlusSceneAccumulator m = TimePlusSceneAccumulator (Time,SceneAccumulator m) deriving (CoordinateSystemClass) instance (Monad m) => ScenicAccumulator (TimePlusSceneAccumulator m) m where accumulateScene slayer scobj (TimePlusSceneAccumulator (t,sceneaccum)) = TimePlusSceneAccumulator (t,accumulateScene slayer scobj sceneaccum) instance RecombinantState (TimePlusSceneAccumulator m) where type SubState (TimePlusSceneAccumulator m) = TimePlusSceneAccumulator m clone = id recombine (TimePlusSceneAccumulator (t,old)) (TimePlusSceneAccumulator (_,new)) = TimePlusSceneAccumulator (t,recombine old new) -- | A monad for animation using RSAGL's scene accumulation system. type AniM a = StateT (TimePlusSceneAccumulator IO) IO a -- | Get's the time of the current frame. frameTime :: AniM Time frameTime = gets (\(TimePlusSceneAccumulator (t,_)) -> t) runAniM :: AniM (a,SceneLayerInfo) -> IO (a,Scene) runAniM anim = do t <- getTime ((a,sli),TimePlusSceneAccumulator (_,sa)) <- runStateT anim $ TimePlusSceneAccumulator (t,null_scene_accumulator) result_scene <- assembleScene sli sa return (a,result_scene) -- | Generates a continuous rotation. rotationM :: Vector3D -> Rate Angle -> AniM AffineTransformation rotationM v a = do t <- frameTime return (rotate v (a `over` t)) -- | Combine an animation with a continuous affine transformation. animateM :: AniM AffineTransformation -> AniM b -> AniM b animateM affineF action = do at <- affineF transformM (affineOf at) action -- | Rotate an animation continuously. rotateM :: Vector3D -> Rate Angle -> AniM a -> AniM a rotateM v a = animateM (rotationM v a) -- | An object that can capture either a monadic or -- arrow-based animation. data AnimationObject i o = AniMObject (i -> AniM o) | AniAObject (FRPProgram (SceneAccumulator IO) i o) newAnimationObjectM :: (i -> AniM o) -> AnimationObject i o newAnimationObjectM = AniMObject newAnimationObjectA :: (forall e. FRP e (FRP1 (SceneAccumulator IO) i o) i o) -> IO (AnimationObject i o) newAnimationObjectA thread = liftM AniAObject $ newFRP1Program thread runAnimationObject :: AnimationObject i o -> i -> AniM o runAnimationObject (AniMObject f) i = f i runAnimationObject (AniAObject frpp) i = do TimePlusSceneAccumulator (t,old_s) <- get (o,new_s) <- liftIO $ updateFRPProgram (Just t) (i,old_s) frpp put $ TimePlusSceneAccumulator (t,new_s) return o