--
module Fal where import SOEGraphics hiding (Point, Region, Event) import qualified SOEGraphics as G (Point, Region, Event) import Draw import Shape import Region import Picture import Animation(picToGraphic) import Memo -- import Drawing (xWin,yWin,intToFloat) import Win32Misc (timeGetTime) import Word (word32ToInt) import Channel infixl 2 =>>, ->> infixl 1 `switch`, `stepAccum`, `step` infixl 0 .|. infixr 4 <*, >* infixr 3 &&* infixr 2 ||* type Time = Float type UserAction = G.Event newtype Behavior1 a = Behavior1 ([(UserAction,Time)] -> Time -> a) inList :: [Int] -> Int -> Bool inList xs y = elem y xs result1 :: [Bool] result1 = map (inList xs) ys xs = [2,4,6,8,10] :: [Int] ys = [3,6,9] :: [Int] result2 :: [Bool] result2 = manyInList xs ys manyInList :: [Int] -> [Int] -> [Bool] manyInList [] _ = [] manyInList _ [] = [] manyInList (x:xs) (y:ys) = if y[Time] -> [a]) newtype Behavior3 a = Behavior3 ([UserAction] -> [Time] -> [a]) newtype Behavior4 a = Behavior4 ([Maybe UserAction] -> [Time] -> [a]) newtype Behavior a = Behavior (([Maybe UserAction],[Time]) -> [a]) newtype Event a = Event (([Maybe UserAction],[Time]) -> [Maybe a]) -- Event a =iso= Behavior (Maybe a) time :: Behavior Time time = Behavior (\(_,ts) -> ts) constB :: a -> Behavior a constB x = Behavior (\_ -> repeat x) ($*) :: Behavior (a->b) -> Behavior a -> Behavior b Behavior ff $* Behavior fb = Behavior (\uts -> zipWith ($) (ff uts) (fb uts)) lift0 :: a -> Behavior a lift0 = constB lift1 :: (a -> b) -> (Behavior a -> Behavior b) lift1 f b1 = lift0 f $* b1 lift2 :: (a -> b -> c) -> (Behavior a -> Behavior b -> Behavior c) lift2 f b1 b2 = lift1 f b1 $* b2 lift3 :: (a -> b -> c -> d) -> (Behavior a -> Behavior b -> Behavior c -> Behavior d) lift3 f b1 b2 b3 = lift2 f b1 b2 $* b3 pairB :: Behavior a -> Behavior b -> Behavior (a,b) pairB = lift2 (,) fstB :: Behavior (a,b) -> Behavior a fstB = lift1 fst sndB :: Behavior (a,b) -> Behavior b sndB = lift1 snd --- COLORS ----- red, blue, yellow, green, white :: Behavior Color red = lift0 Red blue = lift0 Blue yellow = lift0 Yellow green = lift0 Green white = lift0 White --- Shapes, Regions, and Pictures shape :: Behavior Shape -> Behavior Region shape = lift1 Shape region ::Behavior Color -> Behavior Region -> Behavior Picture region = lift2 Region wordPic str pos = lift2 Text pos str showPic n pos = lift2 Text pos (lift1 show n) ell, rec :: Behavior Float -> Behavior Float -> Behavior Region ell x y = shape (lift2 Ellipse x y) rec x y = shape (lift2 Rectangle x y) translate :: (Behavior Float, Behavior Float) -> Behavior Region -> Behavior Region translate (Behavior fx, Behavior fy) (Behavior fp) = Behavior (\uts -> zipWith3 aux (fx uts) (fy uts) (fp uts)) where aux x y p = Translate (x,y) p paint :: Behavior Color -> Behavior Region -> Behavior Picture paint = lift2 Region over :: Behavior Picture -> Behavior Picture -> Behavior Picture over = lift2 Over --- Lifted OPERATORS ---- (>*),(<*), (>=*), (<=*) :: Ord a => Behavior a -> Behavior a -> Behavior Bool (>*) = lift2 (>) (<*) = lift2 (<) (<=*) = lift2 (<=) (>=*) = lift2 (>=) (&&*),(||*) :: Behavior Bool -> Behavior Bool -> Behavior Bool (&&*) = lift2 (&&) (||*) = lift2 (||) instance Fractional a => Fractional (Behavior a) where (/) = lift2 (/) fromRational = lift0 . fromRational instance Num a => Num (Behavior a) where (+) = lift2 (+) (*) = lift2 (*) negate = lift1 negate abs = lift1 abs signum = lift1 signum fromInteger = lift0 . fromInteger instance Show (Behavior a) where showsPrec n a s = "<< Behavior >>" instance Eq (Behavior a) where a1 == a2 = error "Can't compare behaviors." instance Floating a => Floating (Behavior a) where pi = lift0 pi sqrt = lift1 sqrt exp = lift1 exp log = lift1 log sin = lift1 sin cos = lift1 cos tan = lift1 tan asin = lift1 asin acos = lift1 acos atan = lift1 atan sinh = lift1 sinh cosh = lift1 cosh tanh = lift1 tanh asinh = lift1 asinh acosh = lift1 acosh atanh = lift1 atanh --- Simple or Primitive EVENTS lbp :: Event () lbp = Event (\(uas,_) -> map getlbp uas) where getlbp (Just (Button _ True True)) = Just () getlbp _ = Nothing rbp :: Event () rbp = Event (\(uas,_) -> map getrbp uas) where getrbp (Just (Button _ False True)) = Just () getrbp _ = Nothing key :: Event Char key = Event (\(uas,_) -> map getkey uas) where getkey (Just (Key ch True)) = Just ch getkey _ = Nothing mm :: Event Vertex mm = Event (\(uas,_) -> map getmm uas) where getmm (Just (MouseMove pt)) = Just (gPtToPt pt) getmm _ = Nothing gPtToPt :: G.Point -> Vertex gPtToPt (x,y) = ( pixelToInch (x - 300) , pixelToInch (250 - y) ) mouse :: (Behavior Float, Behavior Float) mouse = (fstB m, sndB m) where m = (0,0) `step` mm ---- Behavior and Event Combinators --- switch :: Behavior a -> Event (Behavior a) -> Behavior a Behavior fb `switch` Event fe = memoB $ Behavior (\uts@(us,ts) -> loop us ts (fe uts) (fb uts)) where loop (_:us) (_:ts) ~(e:es) (b:bs) = b : case e of Nothing -> loop us ts es bs Just (Behavior fb') -> loop us ts es (fb' (us,ts)) memoB :: Behavior a -> Behavior a memoB (Behavior fb) = Behavior (memo1 fb) (=>>) :: Event a -> (a->b) -> Event b Event fe =>> f = Event (\uts -> map aux (fe uts)) where aux (Just a) = Just (f a) aux Nothing = Nothing -- Event fe =>> f = Event (map (map f) . fe) e ->> v = e =>> \_ -> v withElem :: Event a -> [b] -> Event (a,b) withElem (Event fe) bs = Event (\uts -> loop (fe uts) bs) where loop (Just a : evs) (b:bs) = Just (a,b) : loop evs bs loop (Nothing : evs) bs = Nothing : loop evs bs withElem_ :: Event a -> [b] -> Event b withElem_ e bs = e `withElem` bs =>> snd (.|.) :: Event a -> Event a -> Event a Event fe1 .|. Event fe2 = Event (\uts -> zipWith aux (fe1 uts) (fe2 uts)) where aux Nothing Nothing = Nothing aux (Just x) _ = Just x aux _ (Just x) = Just x snapshot :: Event a -> Behavior b -> Event (a,b) Event fe `snapshot` Behavior fb = Event (\uts -> zipWith aux (fe uts) (fb uts)) where aux (Just x) y = Just (x,y) aux Nothing _ = Nothing snapshot_ :: Event a -> Behavior b -> Event b snapshot_ e b = e `snapshot` b =>> snd step :: a -> Event a -> Behavior a a `step` e = constB a `switch` e =>> constB stepAccum :: a -> Event (a->a) -> Behavior a a `stepAccum` e = b where b = a `step` (e `snapshot` b =>> uncurry ($)) counter = 0 `stepAccum` lbp ->> (+1) test1 = let Behavior fb = counter in take 20 (fb (uas,ts)) predicate :: Behavior Bool -> Event () predicate (Behavior fb) = Event (\uts -> map aux (fb uts)) where aux True = Just () aux False = Nothing integral :: Behavior Float -> Behavior Float integral (Behavior fb) = Behavior (\uts@(us,t:ts) -> 0 : loop t 0 ts (fb uts)) where loop t0 acc (t1:ts) (a:as) = let acc' = acc + (t1-t0)*a in acc' : loop t1 acc' ts as --- INTERFACE TO THE WINDOW AND USER reactimate :: String -> Behavior a -> (a -> IO Graphic) -> IO () reactimate title franProg toGraphic = runGraphics $ do w <- openWindowEx title (Just (0,0)) (Just (xWin,yWin)) drawBufferedGraphic (Just 30) (us,ts,addEvents) <- windowUser w addEvents let drawPic (Just p) = do g <- toGraphic p setGraphic w g addEvents getWindowTick w drawPic Nothing = return () let Event fe = sample `snapshot_` franProg mapM_ drawPic (fe (us,ts)) sample :: Event () sample = Event (\(us,_) -> map aux us) where aux Nothing = Just () aux (Just _) = Nothing windowUser :: Window -> IO ([Maybe UserAction], [Time], IO ()) windowUser w = do (evs, addEv) <- makeStream t0 <- timeGetTime let addEvents = let loop rt = do mev <- maybeGetWindowEvent w case mev of Nothing -> return () Just e -> addEv (rt, Just e) >> loop rt in do t <- timeGetTime let rt = w32ToTime (t-t0) loop rt addEv (rt, Nothing) return (map snd evs, map fst evs, addEvents) w32ToTime t = intToFloat (word32ToInt t) / 1000 makeStream :: IO ([a], a -> IO ()) makeStream = do ch <- newChan contents <- getChanContents ch return (contents, writeChan ch) ---- PADDLE BALL EXAMPLE paddleball vel = walls `over` paddle `over` ball vel main = test (paddleball 1) walls = let upper = paint blue (translate ( 0,1.7) (rec 4.4 0.05)) left = paint blue (translate (-2.2,0) (rec 0.05 3.4)) right = paint blue (translate ( 2.2,0) (rec 0.05 3.4)) in upper `over` left `over` right paddle = paint red (translate (fst mouse, -1.7) (rec 0.5 0.05)) ball vel = let xvel = vel `stepAccum` xbounce ->> negate xpos = integral xvel xbounce = predicate (xpos >* 2 &&* xvel >* 0 ||* xpos <* -2 &&* xvel <* 0) yvel = vel `stepAccum` ybounce ->> negate ypos = integral yvel roofbounce = ypos >* 1.5 &&* yvel >* 0 paddlebounce = (ypos `between` (-2.0,-1.5)) &&* (fst mouse `between` (xpos-0.25,xpos+0.25)) &&* (yvel <* 0) ybounce = predicate (roofbounce ||* paddlebounce) in (paint yellow (translate (xpos, ypos) (ell 0.2 0.2))) x `between` (a,b) = x >* a &&* x <* b ------ Examples test beh = reactimate "FAL Test" beh (return . picToGraphic) color0 :: Behavior Color color0 = red `switch` lbp ->> blue color1 = red `switch` (lbp `withElem_` cycle [blue,red]) color2 = red `switch` (lbp ->> blue .|. key ->> yellow) color3 = white `switch` (key =>> \c -> case c of 'r' -> red 'b' -> blue 'y' -> yellow _ -> white ) color4 = white `switch` (key `snapshot` color4 =>> \(c,old) -> case c of 'r' -> red 'b' -> blue 'y' -> yellow _ -> constB old) color5 = red `switch` predicate (time >* 5) ->> blue uas = cycle [Nothing, Just (Button (0,0) True True), Nothing] ts = [1,2 ..] :: [Time] test0 = let Behavior fb = color0 in take 3 (fb (uas,ts)) ball1 = paint color4 circle1 circle1 = translate mouse (ell 0.2 0.2) cball0 = paint color0 circle0 cball1 = paint color1 circle0 cball2 = paint color2 circle0 cball3 = paint color3 circle0 cball4 = paint color4 circle0 circle0 = translate (cos time, sin time) (ell 0.2 0.2) --- Ball falling under gravity ball2 = paint red (translate (0,y) (ell 0.2 0.2)) where g = -1 y = 1.5 + integral v v = integral g `switch` (hit `snapshot_` v =>> \v-> lift0 (-v) + integral g) hit = predicate (y <* -1.5 &&* v <* 0) ------------------------------------------------------------------ -- type "test exN" to run example N dot = (ell 0.2 0.2) ex1 = paint red (translate (0, time / 2) dot) ex2 = paint blue (translate (sin time,cos time) dot) wander x y color = paint color (translate (x,y) dot) ex3 = wander (time /2) (sin time) red modula x y = (period,w) where (whole,fract) = properFraction x n = whole `mod` y period = (whole `div` y) w = (fromInt (toInt n)) + fract bounce t = f fraction where (period,fraction) = modula t 2 f = funs !! (period `mod` 4) funs = [id,(2.0 -),negate,(\x -> x - 2.0)] ex4 = wander (lift1 bounce time) 0 yellow moon = (translate (sin time,cos time) dot) ex5 = paint color0 moon ex6 = paint color1 moon ex7 = paint color2 moon ex8 = paint color3 moon ex9 = paint color4 moon growCircle :: Char -> Region growCircle x = Shape(Ellipse (size x) (size x)) size '2' = 0.2 -- size :: Char -> Float size '3' = 0.4 size '4' = 0.6 size '5' = 0.8 size '6' = 1.0 size '7' = 1.2 size '8' = 1.4 size '9' = 1.6 size _ = 0.1 ex10 = paint red (Shape(Ellipse 1 1) `step` (key =>> growCircle)) power2 :: Event(Float -> Float) power2 = (lbp ->> \ x -> x*2) .|. (rbp ->> \ x -> x * 0.5) dynSize = 1.0 `stepAccum` power2 ex11 = paint red (ell dynSize dynSize) ex12 = wander x 0 yellow where xvel = 1 `stepAccum` (hit ->> negate) x = integral xvel left = x <=* -2.0 &&* xvel <*0 right = x >=* 2.0 &&* xvel >*0 hit = predicate (left ||* right) mouseDot = mm =>> \ (x,y) -> translate (constB x,constB y) dot ex13 = paint red (dot `switch` mouseDot) main1 = test ex1 main2 = test ex2 main3 = test ex3 main4 = test ex4 main5 = test ex5 main6 = test ex6 main7 = test ex7 main8 = test ex8 main9 = test ex9 main10 = test ex10 main11 = test ex11 main12 = test ex12 main13 = test ex13 main14 = test paddle main15 = main --