{- Most of the FRP code come from Paul Hudak's book The Haskell School of Expression and has been modified by Maciej Baranski to fit the project purpose-}
module Main where
import Irrlicht
import Data.Time
import Data.Time.Clock.POSIX
import Memo1
import Control.Concurrent.Chan
infixr 1 =>>, ->>
infixr 1 `untilB`, `switch`, `stepAccum`, `step`
infixr 4 <*, >*
infixl 0 .|.
infixr 3 &&*
infixr 2 ||*
type Caption = String
type Counter = Int
caption1, caption2, caption3, caption4 :: Behavior Caption
caption1 = constB "Initial Caption"
caption2 = constB "Any Key Pressed"
caption3 = constB "a Key Pressed"
caption4 = constB "b Key Pressed"
counter1 :: Behavior Counter
counter1 = constB 999
capt1 :: Behavior Caption
capt1 = caption1 `untilB` key ->> caption2
capt2 :: Behavior Caption
capt2 = caption1 `switch` (key =>> \c ->
case c of 'a' -> caption3
'b' -> caption4
_ -> caption1 )
countBeh :: Behavior Counter
countBeh = (0 `stepAccum` key ->> (+1)) `untilB` when (time >* 10) ->> counter1
type Time = POSIXTime
data EventStruct = Key {
char :: Char
}
deriving Show
type UserAction = EventStruct
data GameChan = GameChan {
eventsChan :: Chan UserAction
}
initGameChan :: IO GameChan
initGameChan = do
eventsChan <- newChan
return GameChan {eventsChan = eventsChan }
newtype Behavior a = Behavior (([Maybe UserAction],[Time]) -> [a])
newtype Event a = Event (([Maybe UserAction],[Time]) -> [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
(>*),(<*) :: Ord a => Behavior a -> Behavior a -> Behavior Bool
(>*) = 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."
Behavior fb `untilB` 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') -> fb' (us,ts)
memoB :: Behavior a -> Behavior a
memoB (Behavior fb) = Behavior (memo1 fb)
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))
(=>>) :: Event a -> (a->b) -> Event b
Event fe =>> f = Event (map (fmap f) . fe)
e ->> v = e =>> \_ -> v
unique :: (Show a, Eq a) => Event a -> Event a
unique (Event fe) =
Event (\uts -> aux (fe uts))
where aux xs = zipWith remdup (Nothing:xs) xs
remdup x y | x==y = Nothing
| otherwise = y
when :: Behavior Bool -> Event ()
when = unique . while
while :: Behavior Bool -> Event ()
while (Behavior fb)
= Event (\uts -> map aux (fb uts))
where aux True = Just ()
aux False = Nothing
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 y) = Just y
key :: Event Char
key = Event (\(uas,_) -> map getkey uas)
where getkey (Just (Key ch)) = Just ch
getkey _ = Nothing
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
zipWith' f ~(x:xs) ~(y:ys) = f x y : zipWith' f xs ys
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 ($))
reactimate :: GameChan -> Behavior Caption -> IO ()
reactimate gameCh franProg = do
(user,addEvents) <- windowUser gameCh
addEvents
let drawPic (Just p) = do
running <- deviceRun
videoBeginScene True True 255 200 200 200
sceneDrawAll
guiDrawAll
deviceSetWindowCaption (show p)
ch <- getCharEvent
writeChan (eventsChan gameCh) (Key { char = ch })
videoEndScene
addEvents
drawPic Nothing = return ()
mapM_ drawPic (runEvent (sample `snapshot_` franProg) user)
runEvent (Event fe) u = fe u
sample :: Event ()
sample = Event (\(us,_) -> map aux us)
where aux Nothing = Just ()
aux (Just _) = Nothing
maybeGetWindowEvent :: GameChan -> IO (Maybe UserAction)
maybeGetWindowEvent gameCh = do
noEvents <- isEmptyChan (eventsChan gameCh)
if noEvents
then return Nothing
else do
event <- readChan (eventsChan gameCh)
if ((char event) == ' ')
then return Nothing
else return (Just event)
windowUser :: GameChan -> IO (([Maybe UserAction], [POSIXTime]), IO ())
windowUser gameCh = do
(evs, addEv) <- makeStream
t0 <- getPOSIXTime
let loop rt = do
mev <- maybeGetWindowEvent gameCh
case mev of
Nothing -> return ()
Just e -> do addEv (Just e, rt)
loop rt
let addEvents = do
t <- getPOSIXTime
let rt = t - t0
loop rt
addEv (Nothing, rt)
return ((map fst evs, map snd evs), addEvents)
makeStream :: IO ([a], a -> IO ())
makeStream = do
ch <- newChan
contents <- getChanContents ch
return (contents, writeChan ch)
-- use this game loop if not wanting FRP
gameLoop t0 gameCh=
do
running <- deviceRun
videoBeginScene True True 255 200 200 200
sceneDrawAll
guiDrawAll
ch <- getCharEvent
writeChan (eventsChan gameCh) (Key { char = ch })
videoEndScene
if (running > 0)
then gameLoop t0 gameCh
else return ()
main = do
irrCreateDevice EDT_OPENGL 640 480 False False False
-- make sure to change the path to the map file
fileSystemAddZipFileArchive "/home/maciek/media/map-20kdm2.pk3"
mesh <- sceneGetMesh "20kdm2.bsp"
node <- sceneAddOctTreeSceneNode(mesh)
sceneNodeSetPosition ((-1300), (-144), (-1249)) node
sceneAddCameraSceneNodeFPS
deviceSetEventReceiver 1
gameCh <- initGameChan
--gameLoop t0 gameCh
reactimate gameCh capt2
deviceDrop