reanimate 1.1.5.0 → 1.1.6.0
raw patch · 9 files changed
+112/−48 lines, 9 filesdep −hgeometrydep −hgeometry-combinatorialbinary-addedPVP ok
version bump matches the API change (PVP)
Dependencies removed: hgeometry, hgeometry-combinatorial
API changes (from Hackage documentation)
+ Reanimate: newSpritePart :: Frame s SVG -> Scene s (Sprite s)
+ Reanimate: renderSprite :: Sprite s -> Frame s SVG
+ Reanimate.Scene: newObjectPart :: Renderable a => a -> Scene s (Object s a)
+ Reanimate.Scene: newSpritePart :: Frame s SVG -> Scene s (Sprite s)
+ Reanimate.Scene: renderObject :: Object s a -> Frame s SVG
+ Reanimate.Scene: renderSprite :: Sprite s -> Frame s SVG
Files
- ChangeLog.md +3/−0
- docs/gifs/doc_renderObject.gif binary
- reanimate.cabal +3/−14
- src/Reanimate.hs +2/−0
- src/Reanimate/PolyShape.hs +2/−1
- src/Reanimate/Scene.hs +4/−0
- src/Reanimate/Scene/Object.hs +37/−2
- src/Reanimate/Scene/Sprite.hs +50/−30
- test/Properties.hs +11/−1
ChangeLog.md view
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org)+## 1.1.6.0 -- 2022-06-02++ * Drop hgeometry dependency. ## 1.1.4.0 -- 2021-03-11
+ docs/gifs/doc_renderObject.gif view
binary file changed (absent → 53349 bytes)
reanimate.cabal view
@@ -3,7 +3,7 @@ -- see http://haskell.org/cabal/users-guide/ name: reanimate-version: 1.1.5.0+version: 1.1.6.0 -- synopsis: -- description: license: PublicDomain@@ -37,13 +37,6 @@ Type: git Location: git://github.com/lemmih/reanimate.git -flag no-hgeometry- description:- Disable all features that depend on hgeometry. Should only- be used when developing new hgeometry algorithms.- default: False- manual: True- library hs-source-dirs: src if os(windows)@@ -113,12 +106,7 @@ Detach POVRay autogen-modules: Paths_reanimate- if flag(no-hgeometry)- cpp-options: -DNO_HGEOMETRY- else- build-depends:- hgeometry >=0.11.0.0,- hgeometry-combinatorial >=0.11.0.0+ cpp-options: -DNO_HGEOMETRY build-depends: base >=4.10 && <5, JuicyPixels >=3.3.3,@@ -178,6 +166,7 @@ Helpers hs-source-dirs: test ghc-options: -w+ cpp-options: -DNO_HGEOMETRY build-depends: base, directory,
src/Reanimate.hs view
@@ -105,12 +105,14 @@ , spriteDuration -- :: Frame s Duration , signalS -- :: Sprite s -> Duration -> Signal -> Scene s () , newSprite -- :: Frame s SVG -> Scene s (Sprite s)+ , newSpritePart -- :: Frame s SVG -> Scene s (Sprite s) , newSprite_ -- :: Frame s SVG -> Scene s () , newSpriteA -- :: Animation -> Scene s (Sprite s) , newSpriteA' -- :: Sync -> Animation -> Scene s (Sprite s) , newSpriteSVG -- :: SVG -> Scene s (Sprite s) , newSpriteSVG_ -- :: SVG -> Scene s () , destroySprite -- :: Sprite s -> Scene s ()+ , renderSprite -- :: Sprite s -> Frame s SVG , applyVar -- :: Var s a -> Sprite s -> (a -> SVG -> SVG) -> Scene s () , spriteModify -- :: Sprite s -> Frame s ((SVG,ZIndex) -> (SVG, ZIndex)) -> Scene s () , spriteMap -- :: Sprite s -> (SVG -> SVG) -> Scene s ()
src/Reanimate/PolyShape.hs view
@@ -41,7 +41,7 @@ , plGroupTouching ) where -import Control.Lens ((&), (.~), (^.))+import Control.Lens ((&), (.~)) import Data.List (nub, partition, sortOn) import qualified Data.Vector as V import Geom2D.CubicBezier.Linear (ClosedPath (..),@@ -67,6 +67,7 @@ import Reanimate.Svg #if !defined(NO_HGEOMETRY)+import Control.Lens ((^.)) import Algorithms.Geometry.PolygonTriangulation.Triangulate (triangulate') import Data.Ext
src/Reanimate/Scene.hs view
@@ -39,12 +39,14 @@ spriteT, -- :: Frame s Time spriteDuration, -- :: Frame s Duration newSprite, -- :: Frame s SVG -> Scene s (Sprite s)+ newSpritePart, -- :: Frame s SVG -> Scene s (Sprite s) newSprite_, -- :: Frame s SVG -> Scene s () newSpriteA, -- :: Animation -> Scene s (Sprite s) newSpriteA', -- :: Sync -> Animation -> Scene s (Sprite s) newSpriteSVG, -- :: SVG -> Scene s (Sprite s) newSpriteSVG_, -- :: SVG -> Scene s () destroySprite, -- :: Sprite s -> Scene s ()+ renderSprite, -- :: Sprite s -> Frame s SVG applyVar, -- :: Var s a -> Sprite s -> (a -> SVG -> SVG) -> Scene s () spriteModify, -- :: Sprite s -> Frame s ((SVG,ZIndex) -> (SVG, ZIndex)) -> Scene s () spriteMap, -- :: Sprite s -> (SVG -> SVG) -> Scene s ()@@ -60,6 +62,8 @@ signalO, oNew, newObject,+ newObjectPart,+ renderObject, oModify, oModifyS, oRead,
src/Reanimate/Scene/Object.hs view
@@ -18,7 +18,7 @@ import Reanimate.Svg import Reanimate.Scene.Core (Scene, fork, scene, wait)-import Reanimate.Scene.Sprite (Sprite, newSprite, newSpriteA', play, spriteModify, unVar, signalS)+import Reanimate.Scene.Sprite (Frame, Sprite, addPartToScene, newSpritePart, newSpriteA', play, spriteModify, unVar, signalS, renderSprite) import Reanimate.Scene.Var (Var, modifyVar, newVar, readVar, tweenVar) -------------------------------------------------------@@ -290,6 +290,15 @@ -- | Create new object. newObject :: Renderable a => a -> Scene s (Object s a) newObject val = do+ obj <- newObjectPart val+ addPartToScene $ objectSprite obj+ return obj++-- | Create new object, but not showing as part of the scene, Such+-- objects can be used hierachically within the definitions of+-- sprites, via the function renderObject.+newObjectPart :: Renderable a => a -> Scene s (Object s a)+newObjectPart val = do ref <- newVar ObjectData@@ -306,7 +315,7 @@ _oScale = 1, _oScaleOrigin = V2 0 0 }- sprite <- newSprite $ do+ sprite <- newSpritePart $ do ~obj@ObjectData {..} <- unVar ref pure $ if _oShown@@ -326,6 +335,32 @@ } where svg = toSVG val++-- | Create a frame context from an object for use within a sprite definition.+--+-- Example:+--+-- @+-- do opacityVar <- 'newVar' 1+-- textObj1 <- 'newObjectPart' $ 'scale' 3 $ 'center' $ 'latex' "Fade"+-- 'oModify' textObj1 $ 'oContext' .~ 'withFillColor' "red"+-- textObj2 <- 'newObjectPart' $ 'scale' 3 $ 'center' $ 'latex' "Overlap"+-- 'oModify' textObj2 $ 'oContext' .~ 'withFillColor' "blue"+-- sprite <- 'newSprite' $ do+-- opacity <- 'unVar' opacityVar+-- text1 <- 'renderObject' textObj1+-- text2 <- 'renderObject' textObj2+-- 'return' $ 'withGroupOpacity' opacity $ 'mkGroup' [text1, text2]+-- 'fork' $ 'oShowWith' textObj1 $ 'setDuration' 1 . 'oDraw'+-- 'wait' 0.2+-- 'fork' $ 'oShowWith' textObj2 $ 'setDuration' 1 . 'oDraw'+-- 'wait' 0.2+-- 'tweenVar' opacityVar 1 $ 'const' $ 'fromToS' 1 0+-- @+--+-- <<docs/gifs/doc_renderObject.gif>>+renderObject :: Object s a -> Frame s SVG+renderObject obj = renderSprite $ objectSprite obj oScaleApply :: ObjectData a -> (SVG -> SVG) oScaleApply ObjectData {..} =
src/Reanimate/Scene/Sprite.hs view
@@ -12,7 +12,7 @@ import Reanimate.Animation (Animation, Duration, SVG, Sync (SyncStretch), Time, dropA, duration, getAnimationFrame) import Reanimate.Effect (Effect, delayE)-import Reanimate.Scene.Core (Scene (M), ZIndex, addGen, fork, liftST, queryNow, scene,+import Reanimate.Scene.Core (Gen, Scene (M), ZIndex, addGen, fork, liftST, queryNow, scene, wait) import Reanimate.Scene.Var (Var (..), newVar, readVar, unpackVar) import Reanimate.Transition (Transition, overlapT)@@ -58,22 +58,22 @@ -- | Sprites are animations with a given time of birth as well as a time of death. -- They can be controlled using variables, tweening, and effects.-data Sprite s = Sprite Time (STRef s (Time -> Time)) (STRef s (Duration, ST s (Duration -> Time -> SVG -> (SVG, ZIndex))))+data Sprite s = Sprite Time (STRef s (Time -> Time)) (STRef s (Duration, ST s (Duration -> Duration -> Time -> SVG -> (SVG, ZIndex)))) (Gen s) -- | Sprite frame generator. Generates frames over time in a stateful environment.-newtype Frame s a = Frame {unFrame :: ST s (Time -> Duration -> Time -> a)}+newtype Frame s a = Frame {unFrame :: ST s (Duration -> Time -> Duration -> Time -> a)} instance Functor (Frame s) where fmap fn (Frame gen) = Frame $ do m <- gen- return (\real_t d t -> fn $ m real_t d t)+ return (\scene_d real_t d t -> fn $ m scene_d real_t d t) instance Applicative (Frame s) where- pure v = Frame $ return (\_ _ _ -> v)+ pure v = Frame $ return (\_ _ _ _ -> v) Frame f <*> Frame g = Frame $ do m1 <- f m2 <- g- return $ \real_t d t -> m1 real_t d t (m2 real_t d t)+ return $ \scene_d real_t d t -> m1 scene_d real_t d t (m2 scene_d real_t d t) -- | Dereference a variable as a Sprite frame. --@@ -90,15 +90,15 @@ unVar :: Var s a -> Frame s a unVar var = Frame $ do fn <- unpackVar var- return $ \real_t _d _t -> fn real_t+ return $ \_scene_d real_t _d _t -> fn real_t -- | Dereference seconds since sprite birth. spriteT :: Frame s Time-spriteT = Frame $ return (\_real_t _d t -> t)+spriteT = Frame $ return (\_scene_d _real_t _d t -> t) -- | Dereference duration of the current sprite. spriteDuration :: Frame s Duration-spriteDuration = Frame $ return (\_real_t d _t -> d)+spriteDuration = Frame $ return (\_scene_d _real_t d _t -> d) -- | Create new sprite defined by a frame generator. Unless otherwise specified using -- 'destroySprite', the sprite will die at the end of the scene.@@ -113,17 +113,26 @@ -- <<docs/gifs/doc_newSprite.gif>> newSprite :: Frame s SVG -> Scene s (Sprite s) newSprite render = do+ s <- newSpritePart render+ addPartToScene s+ return s++-- | Create a new sprite defined by a frame generator, but not showing+-- as part of the scene. Such sprites can be used hierarchically within+-- the definitions of other sprites, via the function renderSprite.+newSpritePart :: Frame s SVG -> Scene s (Sprite s)+newSpritePart render = do now <- queryNow tmod <- liftST $ newSTRef id- ref <- liftST $ newSTRef (-1, return $ \_d _t svg -> (svg, 0))- addGen $ do+ ref <- liftST $ newSTRef (-1, return $ \_ad _d _t svg -> (svg, 0))+ return $ Sprite now tmod ref $ do fn <- unFrame render time_fn <- readSTRef tmod (spriteDur, spriteEffectGen) <- readSTRef ref spriteEffect <- spriteEffectGen- return $ \d absT_ ->+ return $ \absD absT_ -> let absT = time_fn absT_- relD = (if spriteDur < 0 then d else spriteDur) - now+ relD = (if spriteDur < 0 then absD else spriteDur) - now relT = absT - now -- Sprite is live [now;duration[ -- If we're at the end of a scene, sprites@@ -131,12 +140,14 @@ -- This behavior is difficult to get right. See the 'bug_*' examples for -- automated tests. inTimeSlice = relT >= 0 && relT < relD- isLastFrame = d == absT && relT == relD- in if inTimeSlice || isLastFrame- then spriteEffect relD relT (fn absT relD relT)+ isLastFrame = absD == absT && relT == relD+ in if inTimeSlice || isLastFrame+ then spriteEffect absD relD relT (fn absD absT relD relT) else (None, 0)- return $ Sprite now tmod ref +addPartToScene :: Sprite s -> Scene s ()+addPartToScene (Sprite _ _ _ gen) = addGen gen+ -- | Create new sprite defined by a frame generator. The sprite will die at -- the end of the scene. newSprite_ :: Frame s SVG -> Scene s ()@@ -197,6 +208,15 @@ newSpriteSVG_ :: SVG -> Scene s () newSpriteSVG_ = void . newSpriteSVG +-- | Create a frame context from the source sprite for use within another. Use of this+-- function allows several sprites to be combined into a single one, with the+-- method of combination controled by variables.+renderSprite :: Sprite s -> Frame s SVG+renderSprite (Sprite _ _ _ gen) =+ Frame $ do+ genFn <- gen+ return (\absD absT _ _ -> fst $ genFn absD absT)+ -- | Change the rendering of a sprite using data from a variable. If data from several variables -- is needed, use a frame generator instead. --@@ -228,7 +248,7 @@ -- -- <<docs/gifs/doc_destroySprite.gif>> destroySprite :: Sprite s -> Scene s ()-destroySprite (Sprite _ _tmod ref) = do+destroySprite (Sprite _ _tmod ref _) = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, render) ->@@ -236,19 +256,19 @@ -- | Low-level frame modifier. spriteModify :: Sprite s -> Frame s ((SVG, ZIndex) -> (SVG, ZIndex)) -> Scene s ()-spriteModify (Sprite born _tmod ref) modFn = liftST $+spriteModify (Sprite born _tmod ref _) modFn = liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do render <- renderGen modRender <- unFrame modFn- return $ \relD relT ->- let absT = relT + born in modRender absT relD relT . render relD relT+ return $ \absD relD relT ->+ let absT = relT + born in modRender absD absT relD relT . render absD relD relT ) -- | Apply easing function before rendering sprite. signalS :: Sprite s -> Duration -> Signal -> Scene s ()-signalS (Sprite _born tmod _ref) dur signal = do+signalS (Sprite _born tmod _ref _) dur signal = do now <- queryNow let modify_t t | t < now = t@@ -271,7 +291,7 @@ -- -- <<docs/gifs/doc_spriteMap.gif>> spriteMap :: Sprite s -> (SVG -> SVG) -> Scene s ()-spriteMap sprite@(Sprite born _ _) fn = do+spriteMap sprite@(Sprite born _ _ _) fn = do now <- queryNow let tDelta = now - born spriteModify sprite $ do@@ -289,7 +309,7 @@ -- -- <<docs/gifs/doc_spriteTween.gif>> spriteTween :: Sprite s -> Duration -> (Double -> SVG -> SVG) -> Scene s ()-spriteTween sprite@(Sprite born _ _) dur fn = do+spriteTween sprite@(Sprite born _ _ _) dur fn = do now <- queryNow let tDelta = now - born spriteModify sprite $ do@@ -331,15 +351,15 @@ -- -- <<docs/gifs/doc_spriteE.gif>> spriteE :: Sprite s -> Effect -> Scene s ()-spriteE (Sprite born _tmod ref) effect = do+spriteE (Sprite born _tmod ref _) effect = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do render <- renderGen- return $ \d t svg ->- let (svg', z) = render d t svg+ return $ \ad d t svg ->+ let (svg', z) = render ad d t svg in (delayE (max 0 $ now - born) effect d t svg', z) ) @@ -357,15 +377,15 @@ -- -- <<docs/gifs/doc_spriteZ.gif>> spriteZ :: Sprite s -> ZIndex -> Scene s ()-spriteZ (Sprite born _tmod ref) zindex = do+spriteZ (Sprite born _tmod ref _) zindex = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do render <- renderGen- return $ \d t svg ->- let (svg', z) = render d t svg in (svg', if t < now - born then z else zindex)+ return $ \ad d t svg ->+ let (svg', z) = render ad d t svg in (svg', if t < now - born then z else zindex) ) -- | Destroy all local sprites at the end of a scene.
test/Properties.hs view
@@ -1,13 +1,17 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -w #-} {-# LANGUAGE TemplateHaskell #-} module Properties where +import Test.Tasty++#if !defined(NO_HGEOMETRY)+ import qualified Data.Vector as V import Linear.V2 import Linear.Vector import Test.QuickCheck-import Test.Tasty import Test.Tasty.QuickCheck import Reanimate.Math.Common@@ -18,6 +22,8 @@ import Debug.Trace ++ prop_pGenerate (PolyParam a) (PolyParam b) (PolyParam c) (PolyParam d) = pIsSimple $ pGenerate [a,b,c,d] @@ -87,3 +93,7 @@ return [] all_props :: TestTree all_props = testProperties "properties" $allProperties+#else+all_props :: TestTree+all_props = testGroup "properties" []+#endif